/*
SQLyog Ultimate v8.32 
MySQL - 5.6.12 : Database - mblog
*********************************************************************
*/

/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mblog` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */;

USE `mblog`;

/*Table structure for table `album` */

DROP TABLE IF EXISTS `album`;

CREATE TABLE `album` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
  `NAME` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '名称',
  `SHOW_IMG` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '封面图',
  `SHOW_FLAG` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '是否展示',
  `INTRODUCTION` varchar(1024) CHARACTER SET utf8 DEFAULT NULL COMMENT '介绍',
  `CREATE_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建时间',
  `CREATOR` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建人',
  `LOCATION` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '地点',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='相册表';

/*Data for the table `album` */

/*Table structure for table `albumimg` */

DROP TABLE IF EXISTS `albumimg`;

CREATE TABLE `albumimg` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `ALBUM_ID` int(11) NOT NULL COMMENT '相册编号',
  `IMG_NAME` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '照片名称',
  `IMG_PATH` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '照片路径',
  `INTRODUCTION` varchar(1024) CHARACTER SET utf8 DEFAULT NULL COMMENT '介绍',
  `ADD_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '添加时间',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='相册照片表';

/*Data for the table `albumimg` */

/*Table structure for table `artical` */

DROP TABLE IF EXISTS `artical`;

CREATE TABLE `artical` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `TITLE` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '标题',
  `SUMMARY` varchar(1024) CHARACTER SET utf8 DEFAULT NULL COMMENT '摘要',
  `CREATE_ID` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建人',
  `CREATE_DATE` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建日期',
  `CREATE_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建时间',
  `UPDATE_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '更新时间',
  `CONTENT` longtext CHARACTER SET utf8 COMMENT '内容',
  `INDEX_PICTURE` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '首页图片',
  `TYPE_ID` int(11) DEFAULT NULL COMMENT '分类',
  `REPRINT_FLAG` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '是否转载',
  `REPRINT_URL` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '转载地址',
  `VIEW_TIMES` int(11) DEFAULT NULL COMMENT '查看次数',
  `LIKE_TIMES` int(11) DEFAULT NULL COMMENT '点赞次数',
  `SHOW_FLAG` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '是否公开',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

/*Data for the table `artical` */

insert  into `artical`(`ID`,`TITLE`,`SUMMARY`,`CREATE_ID`,`CREATE_DATE`,`CREATE_TIME`,`UPDATE_TIME`,`CONTENT`,`INDEX_PICTURE`,`TYPE_ID`,`REPRINT_FLAG`,`REPRINT_URL`,`VIEW_TIMES`,`LIKE_TIMES`,`SHOW_FLAG`) values (1,'Oracle数据库开发常用操作','Oracle数据库，作为最主流最常用的数据库之一，熟悉对它的操作有利于在今后的工作中提高效率。本文主要积累了Oracle数据库在开发过程中遇到的常用操作，后期内容也会不断完善。','hairui623968','2020-04-20','2020-05-09 13:35:33',NULL,'## 表操作\r\n**单表查询**\r\n```sql\r\n查询所有：select t.* from tablename t;\r\n条件查询：select t.* from tablename t where t.column=\'XXX\';\r\n```\r\n\r\n\r\n\r\n\r\n\r\noracle中查看表是否被锁\r\n查看表是否被锁\r\n```sql\r\nSELECT a.sid, b.owner, object_name, object_type\r\nFROM v$lock a, all_objects b\r\nWHERE TYPE = \'TM\'\r\nand a.id1 = b.object_id;\r\n```\r\n\r\n查到的都是被锁的表\r\n这样可以把它杀掉\r\n\r\n```sql\r\nSELECT sid,serial# FROM v$session WHERE sid = &sid;\r\nalter system kill session ‘sid,serial#’;\r\n```\r\n\r\n\r\n\r\n\r\n\r\n','14.jpg',3,'0',NULL,1,0,'Y'),(2,'MySql数据库笔记','mysql是一个轻量级数据库，整理工作中遇到的对mysql数据库操作遇到的问题，包括mysql数据库的安装和使用。','hairui623968','2020-04-21','2020-04-23 11:00:41',NULL,'**问题：mysql数据库查询结果区分大小写？**\r\n> 描述：\r\n在执行如下语句时：select t.* from table1 t where t.name=\'ZAHNGSAN\';在执行完成后结果会显示如：zhangsan Zhangsan ZHANGsan等等，此时我们需要区分大小写进行查询。\r\n解决方法：\r\n```sql\r\n- select t.* from table where binary t.name=\'ZHANGSAN\';\r\n- select t.* from table where t.name= binary \'ZHANGSAN\';\r\n```\r\n\r\n\r\n\r\n**mysql数据库错误提示**\r\n```\r\ncom.mysql.jdbc.PacketTooBigException: Packet for query is too large (175186907 > 4194304)\r\n原因是mysql的max_allowed_packet设置过小引起的\r\n解决方法：查看目前配置\r\nshow VARIABLES like \'%max_allowed_packet%\';\r\n更新\r\nset global max_allowed_packet = 100*1024*1024;\r\n```\r\n\r\n\r\n\r\n\r\n\r\n','11.jpg',3,'0',NULL,2,0,'Y'),(3,'JAVA环境变量的配置','java环境变量','hairui623968','2020-04-21','2020-04-23 10:44:32',NULL,'## windows下的java环境变量配置\r\n右击“计算机”、“属性”、“高级系统设置”、“环境变量”\r\n**新建变量：**\r\n变量名=JAVA_HOME\r\n变量值=C:\\Program Files\\Java\\jdk1.8.0_241\r\n\r\n变量名=CLASSPATH\r\n变量值=.;%JAVA_HOME%/lib;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar\r\n\r\n**编辑变量**\r\n变量名=Path\r\n首部添加=%JAVA_HOME%/bin;%JAVA_HOME%/jre/bin;\r\n','16.jpg',1,'0',NULL,1,1,'Y'),(4,'常用数据库连接信息','常用数据库连接信息','hairui623968','2020-04-22','2020-04-22 15:06:09',NULL,'>** MySQL:**\r\nDriver:com.mysql.jdbc.Driver\r\nURL:jdbc:mysql://localhost:3306/db_name\r\nClass.forName(Driver);\r\nConnection con = DriverManager.getConnection(URL,Username,Password);\r\n\r\n\r\n> **Microsoft SQL Server**\r\nDriver:com.microsoft.jdbc.sqlserver.SQLServerDriver\r\nURL:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=db_name\r\n\r\n\r\n> **SysBase:**\r\nDriver:com.sybase.jdbc.SybDriver\r\nURL:jdbc:Sysbase://localhost:5007/db_name\r\n\r\n\r\n> **Oracle:**\r\nDriver:oracle.jdbc.driver.OracleDriver\r\nURL:jdbc:oracle:thin@localhost:1521:orcl\r\n\r\n> **DB2:**\r\nDriver:com.ibm.db2.jdbc.app.DB2.Driver  (这是连接具有DB2客户端的Provider)\r\nDriver:com.ibm.db2.jdbc.net.DB2.Driver  (这是连接不具有DB2客户端的Provider)\r\nURL:jdbc:db2://localhost:5000/db_name\r\n','23.jpg',3,'0',NULL,0,0,'Y'),(5,'JavaScript正则表达式','JavaScript 有两种方式创建正则表达式：\r\n第一种：直接通过/正则表达式/写出来\r\n第二种：通过new RegExp(\'正则表达式\')创建一个RegExp对象\r\n','hairui623968','2020-04-22','2020-04-26 13:02:25',NULL,'\r\n### 1. 正则表达式创建\r\n\r\n**JavaScript 有两种方式创建正则表达式：**\r\n第一种：直接通过/正则表达式/写出来\r\n第二种：通过new RegExp(\'正则表达式\')创建一个RegExp对象\r\n\r\n    const re1 = /ABC\\-001/;\r\n    const re2 = new RegExp(\'ABC\\\\-001\');\r\n\r\n    re1; // /ABC\\-001/\r\n    re2; // /ABC\\-001/\r\n\r\n注意，如果使用第二种写法，因为字符串的转义问题，字符串的两个\\实际上是一个\\。\r\n### 2. 使用模式\r\n#### 2.1 使用简单模式\r\n\r\n简单的模式是由找到的直接匹配所构成的。比如，/abc/这个模式就匹配了在一个字符串中，仅仅字符 \'abc\' 同时出现并按照这个顺序。在 \"Hi, do you know your abc\'s?\" 和 \"The latest airplane designs evolved from slabcraft.\" 就会匹配成功。在上面的两个实例中，匹配的是子字符串 \'abc\'。在字符串 \"Grab crab\" 中将不会被匹配，因为它不包含任何的 \'abc\' 子字符串。\r\n#### 2.2 使用特殊字符\r\n\r\n例如：模式/abc/匹配了一个单独的 \'a\' 后面跟了零个或者多个 \'b\'（的意思是前面一项出现了零个或者多个），且后面跟着 \'c\' 的任何字符组合。在字符串 \"s\'scbbabbbbcdebc\" 中，这个模式匹配了子字符串 \"abbbbc\"。\r\n\r\n### 3. 应用\r\n#### 3.1 切分字符串\r\n\r\n用正则表达式切分字符串比用固定的字符更灵活，通常的切分代码：\r\n\r\n    \'a d   c\'.split(\' \'); // [\'a\', \'d\', \'\', \'\', \'c\']\r\n\r\n上面方法无法识别连续的空格，改用正则表达式：\r\n\r\n    \'a b   c\'.split(/\\s+/); // [\'a\', \'b\', \'c\']\r\n\r\n无论多少个空格都可以正常分割。再加入‘,’：\r\n\r\n    \'a,b, c  d\'.split(/[\\s\\,]+/); // [\'a\', \'b\', \'c\', \'d\']\r\n\r\n再加入;：\r\n\r\n    \'a,b;; c  d\'.split(/[\\s\\,\\;]+/); // [\'a\', \'b\', \'c\', \'d\']\r\n\r\n所以，可以用正则表达式来把不规范的输入转化成正确的数组。\r\n#### 3.2 分组\r\n\r\n除了判断是否匹配之外，正则表达式还可以提取子串，用()表示的就是要提取的分组（Group）。比如：\r\n\r\n^(\\d{4})-(\\d{4,9})$分别定义了两个组，可以直接从匹配的字符串中提取出区号和本地号码：\r\n\r\n    var re = /^(\\d{4})-(\\d{4,9})$/;\r\n    re.exec(\'0530-12306\'); // [\'010-12345\', \'010\', \'12345\']\r\n    re.exec(\'0530 12306\'); // null\r\n\r\nexec()方法在匹配成功后，返回一个数组，第一个元素是正则表达式匹配到的整个字符串，后面的字符串表示匹配成功的子串。\r\n\r\nexec()方法在匹配失败时返回null。\r\n#### 3.3 贪婪匹配\r\n\r\n注意，正则匹配默认是贪婪匹配，也就是匹配尽可能多的字符。如下，匹配出数字后面的0：\r\n\r\n    var re = /^(\\d+)(0*)$/;\r\n    re.exec(\'102300\'); // [\'102300\', \'102300\', \'\']\r\n\r\n由于\\d+采用贪婪匹配，直接把后面的0全部匹配了，结果0*只能匹配空字符串了。\r\n\r\n必须让\\d+采用非贪婪匹配（也就是尽可能少匹配），才能把后面的0匹配出来，加个?就可以让\\d+采用非贪婪匹配：\r\n\r\n    var re = /^(\\d+?)(0*)$/;\r\n    re.exec(\'102300\'); // [\'102300\', \'1023\', \'00\']\r\n\r\n#### 3.4 正则表达式标志\r\n\r\ng	全局搜索。\r\ni	不区分大小写搜索。\r\nm	多行搜索。\r\ny	执行“粘性”搜索,匹配从目标字符串的当前位置开始，可以使用y标志。\r\n\r\n3.6 test() 方法\r\n\r\ntest() 方法用于检测一个字符串是否匹配某个模式，如果字符串中含有匹配的文本，则返回 true，否则返回 false。\r\n\r\n    var re = /^(\\d{4})-(\\d{4,9})$/;\r\n    re.test(\'0530-12321\'); // true\r\n    re.test(\'0530-123ab\'); // false\r\n    re.test(\'0530 12321\'); // false\r\n\r\n### 4. 常用正则（参考）\r\n\r\n\r\n验证Email地址：^\\w+[-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$\r\n验证身份证号（15位或18位数字）：^\\d{15}|\\d{}18$\r\n\r\n中国大陆手机号码：1\\d{10}\r\n中国大陆固定电话号码：(\\d{4}-|\\d{3}-)?(\\d{8}|\\d{7})\r\n中国大陆邮政编码：[1-9]\\d{5}\r\n\r\nIP地址：((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\r\n\r\n日期(年-月-日)：(\\d{4}|\\d{2})-((1[0-2])|(0?[1-9]))-(([12][0-9])|(3[01])|(0?[1-9]))\r\n日期(月/日/年)：((1[0-2])|(0?[1-9]))/(([12][0-9])|(3[01])|(0?[1-9]))/(\\d{4}|\\d{2})\r\n\r\n验证数字：^[0-9]*$\r\n验证n位的数字：^\\d{n}$\r\n验证至少n位数字：^\\d{n,}$\r\n验证m-n位的数字：^\\d{m,n}$\r\n验证零和非零开头的数字：^(0|[1-9][0-9]*)$\r\n验证有1-3位小数的正实数：^[0-9]+(.[0-9]{1,3})?$\r\n验证非零的正整数：^\\+?[1-9][0-9]*$\r\n验证非零的负整数：^\\-[1-9][0-9]*$\r\n验证非负整数（正整数 + 0） ^\\d+$\r\n验证非正整数（负整数 + 0） ^((-\\d+)|(0+))$\r\n验证长度为3的字符：^.{3}$\r\n验证由26个英文字母组成的字符串：^[A-Za-z]+$\r\n验证由26个大写英文字母组成的字符串：^[A-Z]+$\r\n验证由26个小写英文字母组成的字符串：^[a-z]+$\r\n验证由数字和26个英文字母组成的字符串：^[A-Za-z0-9]+$\r\n\r\n','32.jpg',7,'0',NULL,0,0,'Y'),(6,'CentOS 6下安装Apache反向代理','平台：centos6.0 64位\r\n安装环境：gcc,gcc-c++编译器/java环境\r\n反向代理：可以突破网络限制，进行节点之间的网络互相转换，实现非直连网络之间的访问。','hairui623968','2020-04-23','2020-04-23 10:28:53',NULL,'### 环境准备\r\n平台：centos6.0 64位\r\n安装环境：gcc,gcc-c++编译器/java环境\r\n### 步骤\r\n1.一般安装完成之后系统会自带apache的web服务，卸载自带httpd服务。\r\n> rmp -e httpd –nodeps;\r\n\r\n2.下载安装httpd服务所需的文件(本例中以tar.gz包为示例)\r\n> apr-1.4.5.tar.gz\r\napr-util-1.3.12.tar.gz\r\npcre-8.10.tar.gz\r\nhttpd-2.4.17.tar.gz\r\n\r\n将如上文件拷贝到/home下\r\n\r\n3.安装apr包\r\n> tar -zxvf /home/apr-1.4.5.tar.gz\r\ncd /home/apr-1.4.5\r\n./configure --prefix=/usr/local/apr/\r\nmake && make install\r\n\r\n4.安装apr-util包\r\n> tar -zxvf apr-util-1.3.12.tar.gz\r\ncd /home/apr-util-1.3.12\r\n./configure --prefix=/usr/local/apr-util/ --with-apr=/usr/local/apr/\r\nmake && make install\r\n\r\n5.安装pcre包\r\n> tar -zxvf pcre-8.10.tar.gz\r\ncd /home/pcre-8.10/\r\n./configure --prefix=/usr/local/pcre/\r\nmake && make install\r\n\r\n6.安装httpd包\r\n> tar -zxvf httpd-2.4.17.tar.gz\r\ncd /home/httpd-2.4.17\r\n./configure --prefix=/usr/local/apache --enable-so --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --with-pcre=/usr/local/pcre\r\nmake && make install\r\n\r\n7.配置http.conf文件 /apache/conf/httpd.conf\r\n添加ServerName localhost:80\r\n启动httpd服务，访问localhost显示 **it works!**\r\n\r\n开启以下模块\r\n> LoadModule proxy_module modules/mod_proxy.so\r\nLoadModule proxy_connect_module modules/mod_proxy_connect.so\r\nLoadModule proxy_http_module modules/mod_proxy_http.so\r\n\r\n设置虚拟代理\r\n	# Virtual hosts\r\n	Include conf/extra/httpd-vhosts.conf\r\n\r\n8.配置httpd-vhosts.conf文件 /apache/conf/extra/httpd-vhost.conf\r\n> <VirtualHost *:80>\r\n\\#ServerName 客户端访问url名称\r\n\\#ServerAlias url别名\r\n\\#ErrorLog 错误日志\r\n\\#CustomLog 访问记录日志\r\n\\#ProxyRequests 正向代理\r\n\\#<Proxy *> 权限配置\r\n\r\n> ServerName test.ccab.com\r\nServerAlias test.ccab.com/cmis-main\r\nErrorLog \"logs/dummy-host.localhost-error.log\"\r\nCustomLog \"logs/dummy-host.localhost-access.log\" common\r\n>\r\n\\#启用了反向代理，以下ProxyRequests正向代理必须关闭 Off\r\n>\r\n> ProxyRequests Off\r\n<Proxy *>\r\nOrder deny,allow\r\n\\#Deny from all\r\n\\#Allow from 192.168.1.1 192.168.1.2\r\nAllow from all\r\n</Proxy>\r\n\r\n> 	#必须按照以下顺序设置\r\n\r\n> \\#ProxyPassReverse / http://localhost:9080/cmis-main/\r\nProxyPass /cmis-main/ http://localhost:9080/cmis-main/\r\nProxyPassReverse /cmis-main/ http://localhost:9080/cmis-main/\r\nProxyPass / http://localhost:9080/cmis-main/\r\n</VirtualHost>\r\n\r\n如果客户机无法访问代理服务器，需要关闭防火墙。\r\n> Iptables -nL -----查看防火墙状态\r\niptables -F ------关闭防火墙\r\n\r\n\r\n\r\n\r\n','13.jpg',2,'0',NULL,0,0,'Y'),(7,'Linux下的常用操作命令','Linux作为主流服务器选择，对其的学习与掌握非常重要，本文就Linux中常用的命令操作进行了整理汇总。','hairui623968','2020-04-23','2020-04-23 10:32:06',NULL,NULL,'12.jpg',2,'0',NULL,1,0,'Y'),(8,'阿里巴巴Java开发手册（华山版）','《Java开发手册》是阿里巴巴集团技术团队的集体智慧结晶和经验总结，经历了多次大规模一线实战的检验及不断完善，公开到业界后，众多社区开发者踊跃参与，共同打磨完善，系统化地整理成册。现代软件行业的高速发展对开发者的综合素质要求越来越高，因为不仅是编程知识点，其它维度的知识点也会影响到软件的最终交付质量','hairui623968','2020-04-23','2020-04-23 10:40:52',NULL,'## 前 言\r\n《Java开发手册》是阿里巴巴集团技术团队的集体智慧结晶和经验总结，经历了多次大规模一线实战的检验及不断完善，公开到业界后，众多社区开发者踊跃参与，共同打磨完善，系统化地整理成册。现代软件行业的高速发展对开发者的综合素质要求越来越高，因为不仅是编程知识点，其它维度的知识点也会影响到软件的最终交付质量。比如：数据库的表结构和索引设计缺陷可能带来软件上的架构缺陷或性能风险；工程结构混乱导致后续维护艰难；没有鉴权的漏洞代码易被黑客攻击等等。所以本手册以Java开发者为中心视角，划分为编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约七个维度，再根据内容特征，细分成若干二级子目录。另外，依据约束力强弱及故障敏感性，规约依次分为强制、推荐、参考三大类。在延伸信息中，“说明”对规约做了适当扩展和解释；“正例”提倡什么样的编码和实现方式；“反例”说明需要提防的雷区，以及真实的错误案例。\r\n手册的愿景是码出高效，码出质量。现代软件架构的复杂性需要协同开发完成，如何高效地协同呢？无规矩不成方圆，无规范难以协同，比如，制订交通法规表面上是要限制行车权，实际上是保障公众的人身安全，试想如果没有限速，没有红绿灯，谁还敢上路行驶？对软件来说，适当的规范和标准绝不是消灭代码内容的创造性、优雅性，而是限制过度个性化，以一种普遍认可的统一方式一起做事，提升协作效率，降低沟通成本。代码的字里行间流淌的是软件系统的血液，质量的提升是尽可能少踩坑，杜绝踩重复的坑，切实提升系统稳定性，码出质量。\r\n我们已经在2017杭州云栖大会上发布了配套的Java开发规约IDE插件，阿里云效也集成了代码规约扫描引擎。次年，发布36万字的配套详解图书《码出高效》，本书秉持“图胜于表，表胜于言”的理念，深入浅出地将计算机基础、面向对象思想、JVM探源、数据结构与集合、并发与多线程、单元测试等知识客观、立体地呈现出来。紧扣学以致用、学以精进的目标，结合阿里巴巴实践经验和故障案例，与底层源码解析融会贯通，娓娓道来。此书所得收入均捐赠公益事情，希望用技术情怀帮助更多的人。\r\n\r\n\r\n','21.jpg',1,'0',NULL,1,1,'Y'),(9,'使用Editor.md实现Markdown文本编辑功能','Markdown作为主流的弱文本编辑器，已经越来越广泛的用于各类网站，这里就如何在springboot项目中使用markdown文本编辑功能，并解决在环境集成过程中遇到的一些问题进行总结。','hairui623968','2020-04-23','2020-04-23 11:09:38',NULL,'#### 什么是markdown：\r\n	官方解释：Markdown是一种可以使用普通文本编辑器编写的标记语言，通过简单的标记语法，它可以使普通文本内容具有一定的格式。\r\n	通俗来讲：就是一种能够定义特殊样式标记的约定语言。例如在文字前面添加 > 然后再加上文字，展现出来的就是引用的效果，比如下面这样。\r\n> 这是一个引用\r\n\r\n#### 如何将markdown集成到项目中\r\n首先我们需要明确markdown有什么作用，为了实现某些页面的实时编辑，我们需要引入markdown来进行文字写作。所以，如何将markdown与项目整合起来，这是重点。\r\n\r\n目前市面上有很多markdown编辑工具，这里我选择了edit.md，这也是大家比较推崇的一款产品。大家可以前往官网了解这款产品，地址是：[https://pandao.github.io/editor.md/examples/][https://pandao.github.io/editor.md/examples/]\r\n[https://pandao.github.io/editor.md/examples/]: https://pandao.github.io/editor.md/examples/ \"https://pandao.github.io/editor.md/examples/\"\r\n\r\n1. 下载插件，下载完成插件后，将插件解压存放到项目对应的位置，我这里单独创建了一个editmd文件夹，将内容存放于此。如图：\r\n![](/myblog/upload/363503b1-3a6e-4285-8513-5df04ebccb66.jpg)\r\n\r\n2. 创建编辑页面，这里我创建一个editmd-edit.html页面，并已引入相关css js。（我的jquery版本为3.3.1，大家可以根据自己的情况进行修改）\r\n````html\r\n<script src=\"js/jquery-3.3.1.min.js\"></script>\r\n<script type=\"text/javascript\" src=\"editormd/editormd.min.js\">\r\n<link href=\"editormd/css/editormd.min.css\" rel=\"stylesheet\" type=\"text/css\"/>\r\n````\r\n设置编辑器属性：\r\n```javascript\r\n<script type=\"text/javascript\">\r\n        var testEditor;\r\n        testEditor = $(function () {\r\n            editormd(\"test-editormd\", {\r\n                width: \"90%\",\r\n                height: 640,\r\n                //markdown : md,//不注释不显示\r\n                codeFold: true,\r\n                syncScrolling: \"single\",\r\n                path: \"editormd/lib/\", //你的path路径（原资源文件中lib包在我们项目中所放的位置）\r\n                imageUpload: true,//开启图片上传功能\r\n                /*\r\n                theme: \"dark\",//工具栏主题\r\n                previewTheme: \"dark\",//预览主题\r\n                editorTheme: \"pastel-on-dark\",//编辑主题\r\n                */\r\n                emoji: true,//emoji表情，默认关闭\r\n                taskList: true,\r\n                tocm: true,         // Using [TOCM]\r\n                tex: true,                   // 开启科学公式TeX语言支持，默认关闭\r\n                flowChart: true,             // 开启流程图支持，默认关闭\r\n                sequenceDiagram: true,       // 开启时序/序列图支持，默认关闭,\r\n                dialogLockScreen: false,//设置弹出层对话框不锁屏，全局通用，默认为true\r\n                dialogShowMask: false,//设置弹出层对话框显示透明遮罩层，全局通用，默认为true\r\n                dialogDraggable: false,//设置弹出层对话框不可拖动，全局通用，默认为true\r\n                dialogMaskOpacity: 0.4, //设置透明遮罩层的透明度，全局通用，默认值为0.1\r\n                dialogMaskBgColor: \"#000\",//设置透明遮罩层的背景颜色，全局通用，默认为#fff\r\n                //这个配置在simple.html中并没有，但是为了能够提交表单，使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中，方便post提交表单。\r\n                saveHTMLToTextarea: true,\r\n                imageFormats: [\"jpg\", \"jpeg\", \"gif\", \"png\", \"bmp\"],\r\n                imageUploadURL: \"/uploadimg/\",/*上传图片成功后可以做一些自己的处理*/\r\n            });\r\n        });\r\n    </script>\r\n```\r\n构造表单用于提交内容：\r\n```html\r\n<form th:action=\"editmd-data\" method=\"post\">\r\n    <br/>\r\n    <div class=\"editormd\" id=\"test-editormd\">\r\n        <textarea class=\"editormd-markdown-textarea\" name=\"test-editormd-markdown-doc\" id=\"editormd\" th:text=\"${content}\"></textarea>\r\n        <!-- 第二个隐藏文本域，用来构造生成的HTML代码，方便表单POST提交，这里的name可以任意取，后台接受时以这个name键为准 -->\r\n        <!-- html textarea 需要开启配置项 saveHTMLToTextarea == true -->\r\n        <textarea class=\"editormd-html-textarea\" name=\"editorhtml\" id=\"editorhtml\"></textarea></div>\r\n    <div align=\"center\">\r\n        <input type=\"submit\" class=\"btn-lg\" value=\"提交\" style=\"background: #009A61\" align=\"center\">\r\n    </div>\r\n</form>\r\n```\r\n\r\n后台表单提交controller：\r\n```java\r\n @RequestMapping(value = \"/editmd-data\")\r\n    public String editmdSubmitPageTest(HttpServletRequest httpServletRequest, Model model) {\r\n        String content = httpServletRequest.getParameter(\"test-editormd-markdown-doc\");\r\n        editmdService.saveContent(content);\r\n        model.addAttribute(\"content\", content);\r\n        return \"editmd/editmd-view\";\r\n    }\r\n```\r\n\r\n查看页面editmd-view：\r\n```html\r\n<script type=\"text/javascript\">\r\n        $(function () {\r\n            var testEditormdView;\r\n            testEditormdView = editormd.markdownToHTML(\"test-editormd-view\", {\r\n                htmlDecode: \"style,script,iframe\",  // you can filter tags decode\r\n                emoji: true,\r\n                taskList: true,\r\n                tex: true,  // 默认不解析\r\n                flowChart: true,  // 默认不解析\r\n                sequenceDiagram: true,  // 默认不解析\r\n            });\r\n        });\r\n    </script>\r\n```\r\n```html\r\ndiv id=\"test-editormd-view\">\r\n        <textarea id=\"append-test\" th:text=\"${content}\"></textarea>\r\n    </div>\r\n```\r\n这里使用了thymeleaf获取后台内容。效果如下图：\r\n![](/myblog/upload/e2611690-3947-4ad5-887e-eba0708957fa.jpg)\r\n\r\n\r\n','28.jpg',7,'0',NULL,0,0,'Y'),(10,'Apache Maven 3.6.0安装配置','Maven 除了以程序构建能力为特色之外，还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性，所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法，许多 Apache Jakarta 项目发文时使用 Maven，而且公司项目采用 Maven 的比例在持续增长','hairui623968','2020-04-23','2020-04-23 11:03:34',NULL,'Maven 除了以程序构建能力为特色之外，还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性，所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法，许多 Apache Jakarta 项目发文时使用 Maven，而且公司项目采用 Maven 的比例在持续增长。\r\n- 第一步：下载maven安装包\r\n下载地址：http://maven.apache.org/download.cgi  注意下载bin文件 src为源码\r\n![](/myblog/upload/17100f59-c0ff-485a-848a-b905d6023409.png)\r\n- 第二步：解压下载文件\r\n将下载的压缩包解压，例如：D:\\Program Files\\apache-maven-3.6.0\r\n![](/myblog/upload/8ba34a35-23f9-433a-b884-2c66969ec447.png)\r\n- 第三步：配置maven环境变量\r\n新建环境变量MAVEN_HOME 并添加路径值D:\\Program Files\\apache-maven-3.6.0\r\n![](/myblog/upload/80d82e13-c9eb-416f-bcc8-877428360524.png)\r\n编辑环境变量Path，添加%MAVEN_HOME%\\bin\\\r\n![](/myblog/upload/cc158587-30a9-4a2e-8150-23d85035e276.png)\r\n进入dos 输入mvn -v查看maven是否正确安装\r\n![](/myblog/upload/07468f25-0f92-4b3b-810c-a640d3576ac1.png)\r\n配置Maven本地仓库\r\n打开文件D:\\Program Files\\apache-maven-3.6.0\\conf\\setting.xml\r\n找到如下代码：<localRepository>/path/to/local/repo</localRepository>\r\n我们可以看到，此段代码已经被注释了，需要取消注释，同时将值修改为本地路径，我这里选择D:\\Program Files\\apache-maven-3.6.0\\repo为本地maven仓库路径。\r\n（配置本地仓库的目的是为了能够更加快速的查找我们在程序开发的过程中需要用到的依赖包，如果本地仓库存在，则直接从仓库中获取，如果不存在，则会去远程仓库下载并保存到本地仓库）\r\n修改前\r\n![](/myblog/upload/5ce2166d-96a1-4ddc-b041-c95c793a865b.png)\r\n修改后\r\n![](/myblog/upload/31701e02-dbf2-4296-96be-55c9b7041cbf.png)\r\n配置阿里云镜像仓库\r\n在settings.xml文件中的mirrors下添加mirror标签\r\n```xml\r\n<mirror>\r\n<id>alimaven</id>\r\n<name>aliyun maven</name>\r\n<url>http://maven.aliyun.com/nexus/content/groups/public/</url>\r\n<mirrorOf>central</mirrorOf>\r\n</mirror>\r\n```\r\n\r\n验证之前配置是否生效，命令窗口输入：mvn help:system\r\n\r\n可以发现，maven已经从阿里云镜像中下载了部分相关文件到本地配置路径下\r\n![](/myblog/upload/20efed44-a106-4fa4-ba71-59698353302a.png)\r\n\r\n至此，Maven的安装和配置都已经完成，','29.jpg',1,'0',NULL,1,0,'Y'),(11,'web项目常见错误汇总','java.lang.IllegalStateException: Web app root system property already set to different value: \'webapp.root\' = [....\\tmp1\\wtpwebapps\\workreport\\] instead of [.....\\wtpwebapps\\ApprovalFront\\] \r\n- Choose unique values for the \'webAppRootKey\' context-param in your web.xml files!','hairui623968','2020-04-23','2020-04-26 12:55:32',NULL,'```html\r\njava.lang.IllegalStateException: Web app root system property already set to different value: \'webapp.root\' = [....\\tmp1\\wtpwebapps\\workreport\\] instead of [.....\\wtpwebapps\\ApprovalFront\\] \r\n- Choose unique values for the \'webAppRootKey\' context-param in your web.xml files!\r\n \r\n错误原因：Tomcat发布多个项目时抛的webAppRootKey错误,  原因是部署在同一容器中的Web项目，定义了相同的webAppRootKey或者都没有定义\r\n解决办法：需要为每个web都定义一个webAppRootKey\r\n<!--app1中的web.xml-->\r\n<context-param>\r\n    <param-name>webAppRootKey</param-name>\r\n    <param-value>app1name</param-value>\r\n</context-param>\r\n \r\n<!--app2中的web.xml-->\r\n<context-param>\r\n    <param-name>webAppRootKey</param-name>\r\n    <param-value>app2name</param-value>\r\n</context-param>\r\n```','34.jpg',1,'0',NULL,0,0,'Y'),(12,'过滤器、监听器、拦截器简介及其在SpringBoot中的应用','过滤器：依赖与servlet容器，对几乎所有的请求起作用，在容器启动是初始化调用init方法，以后每个请求都调用doFilter()，主要的用途是过滤字符编码、做一些业务逻辑判断等。其工作原理是，它是随你的web应用启动而启动的，只初始化一次，以后就可以拦截相关请求，只有当你的web应用停止或重新部署的时候才销毁。\r\n\r\n监听器：Listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。一般是获取在线人数等业务需求。\r\n\r\n拦截器：是在面向切面编程的就是在你的service或者一个方法，前调用一个方法，或者在方法后调用一个方法比如动态代理就是拦截器的简单实现，spring的aop中的前置通知和后置通知。','hairui623968','2020-04-23','2020-04-23 11:04:03',NULL,'**过滤器**：依赖与servlet容器，对几乎所有的请求起作用，在容器启动是初始化调用init方法，以后每个请求都调用doFilter()，主要的用途是过滤字符编码、做一些业务逻辑判断等。其工作原理是，它是随你的web应用启动而启动的，只初始化一次，以后就可以拦截相关请求，只有当你的web应用停止或重新部署的时候才销毁。\r\n\r\n**监听器**：Listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。一般是获取在线人数等业务需求。\r\n\r\n**拦截器**：是在面向切面编程的就是在你的service或者一个方法，前调用一个方法，或者在方法后调用一个方法比如动态代理就是拦截器的简单实现，spring的aop中的前置通知和后置通知。\r\n\r\n**过滤器在SpringBoot中的应用**\r\n```java\r\n//注册器名称为customFilter,拦截的url为所有\r\n@WebFilter(filterName=\"customFilter\",urlPatterns={\"/*\"})\r\n@Slf4j\r\npublic class CustomFilter implements Filter{\r\n    @Override\r\n    public void init(FilterConfig filterConfig) throws ServletException {\r\n        log.info(\"filter 初始化\");\r\n    }\r\n    @Override\r\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\r\n            throws IOException, ServletException {\r\n        // TODO Auto-generated method stub\r\n        log.info(\"doFilter 请求处理\");\r\n        //对request、response进行一些预处理\r\n        // 比如设置请求编码\r\n        // request.setCharacterEncoding(\"UTF-8\");\r\n        // response.setCharacterEncoding(\"UTF-8\");\r\n        //TODO 进行业务逻辑\r\n        //链路 直接传给下一个过滤器\r\n        chain.doFilter(request, response);\r\n    }\r\n    @Override\r\n    public void destroy() {\r\n        log.info(\"filter 销毁\");\r\n    }\r\n}\r\n```\r\n\r\n然后在启动类加入@ServletComponentScan注解即可。\r\n```java\r\n@SpringBootApplication\r\n@ServletComponentScan\r\n@Slf4j\r\npublic class Chapter7Application {\r\n    public static void main(String[] args) {\r\n        SpringApplication.run(Chapter7Application.class, args);\r\n        log.info(\"chapter7 服务启动\");\r\n    }\r\n}\r\n```\r\n\r\n方式二：启动类中利用@bean注册FilterRegistrationBean\r\n```java\r\n@Bean\r\npublic FilterRegistrationBean  filterRegistrationBean() {\r\n	FilterRegistrationBean registration = new FilterRegistrationBean();\r\n	//当过滤器有注入其他bean类时，可直接通过@bean的方式进行实体类过滤器，这样不可自动注入过滤器使用的其他bean类。\r\n	//当然，若无其他bean需要获取时，可直接new CustomFilter()，也可使用getBean的方式。\r\n	registration.setFilter(customFilter());\r\n	//过滤器名称\r\n	registration.setName(\"customFilter\");\r\n	//拦截路径\r\n	registration.addUrlPatterns(\"/*\");\r\n	//设置顺序\r\n	registration.setOrder(10);\r\n	return registration;\r\n}\r\n@Bean\r\npublic Filter customFilter() {\r\n	return new CustomFilter();\r\n}\r\n```\r\n监听器在SpringBoot中的应用\r\n```java\r\n@WebListener\r\n@Slf4j\r\npublic class Customlister implements ServletRequestListener{\r\n    @Override\r\n    public void requestDestroyed(ServletRequestEvent sre) {\r\n        log.info(\"监听器：销毁\");\r\n    }\r\n    @Override\r\n    public void requestInitialized(ServletRequestEvent sre) {\r\n        log.info(\"监听器：初始化\");\r\n    }\r\n}\r\n```\r\n和创建过滤器一样，在启动类中加入@ServletComponentScan进行自动注册即可。\r\n\r\n拦截器在SpringBoot中的应用\r\n```java\r\n@Slf4j\r\npublic class CustomHandlerInterceptor implements HandlerInterceptor{\r\n\r\n    @Override\r\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)\r\n            throws Exception {\r\n        log.info(\"preHandle:请求前调用\");\r\n        //返回 false 则请求中断\r\n        return true;\r\n    }\r\n\r\n    @Override\r\n    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,\r\n            ModelAndView modelAndView) throws Exception {\r\n        log.info(\"postHandle:请求后调用\");\r\n\r\n    }\r\n\r\n    @Override\r\n    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)\r\n            throws Exception {\r\n        log.info(\"afterCompletion:请求调用完成后回调方法，即在视图渲染完成后回调\");\r\n\r\n    }\r\n\r\n}\r\n```\r\n\r\n通过继承WebMvcConfigurerAdapter注册拦截器\r\n```java\r\n@Configuration\r\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter{\r\n    @Override\r\n     public void addInterceptors(InterceptorRegistry registry) {\r\n         //注册拦截器 拦截规则\r\n        //多个拦截器时 以此添加 执行顺序按添加顺序\r\n        registry.addInterceptor(getHandlerInterceptor()).addPathPatterns(\"/*\");\r\n     }\r\n    @Bean\r\n    public static HandlerInterceptor getHandlerInterceptor() {\r\n        return new CustomHandlerInterceptor();\r\n    }\r\n}\r\n```','25.jpg',1,'0',NULL,2,0,'Y'),(13,'Java集合体系','集合类是Java数据结构的实现。Java的集合类是java.util包中的重要内容，它允许以各种方式将元素分组，并定义了各种使这些元素更容易操作的方法。Java集合类是Java将一些基本的和使用频率极高的基础类进行封装和增强后再以一个类的形式提供。集合类是可以往里面保存多个对象的类，存放的是对象，不同的集合类有不同的功能和特点，适合不同的场合，用以解决一些实际问题。','hairui623968','2020-04-23','2020-04-26 12:54:23',NULL,'\r\n## 1. Collection\r\n最基本的集合接口\r\n一个Collection代表一组Object的集合\r\n```java\r\npublic interface Collection<E> extends Iterable<E>\r\njava.util.Collection的子接口包括：\r\njava.util.Set\r\n    java.util.SortedSet\r\n    java.util.NavigableSet\r\njava.util.Queue\r\n    java.util.concurrent.BlockingQueue\r\n    java.util.concurrent.TransferQueue\r\njava.util.Deque\r\n    java.util.concurrent.BlockingDeque\r\n```\r\n\r\n任何实现Collection接口的类，都必须实现iterator方法来提供遍历集合中的元素\r\n```java\r\nIterator<T> iterator();\r\n```\r\n\r\n例如List中集合的遍历可以采用如下方式\r\n```java\r\nList<String> stringList = Arrays.asList(array);\r\nIterator<String> iterator = stringList.iterator();\r\nwhile(iterator.hasNext()){\r\n    System.out.printf(iterator.next());\r\n}\r\n```\r\n\r\n值得注意的是，Collection和Collectors的区别，Collection是集合的接口，所有的集合类都实现该接口；Collectors是一个类，提供了sort方法对集合进行排序。\r\n\r\n### 1.1.List\r\nList代表元素有序，可重复的集合，集合中每个元素都有对应的顺序索引，允许加入重复元素，通过索引指定元素的位置，实现有ArrayList,Vector,Queue。\r\n\r\n#### 1.1.1 ArrayList\r\n\r\nArrayList是基于数组的实现，封装了一个动态增长，允许再分配的Object[]数组。\r\n\r\n#### 1.1.2 Vector\r\n```java\r\npublic class Vector<E>\r\n    extends AbstractList<E>\r\n    implements List<E>, RandomAccess, Cloneable, java.io.Serializable\r\n```\r\n\r\n使用方法和ArrayList基本相同，子类有Stack。和ArrayList区别是Vector是线程安全的，对集合元素操作的时候都加了Synchronized，保证线程的安全；在扩容时，Vector默认增长一倍的容量，而List只增长50%;\r\n\r\n##### 1.1.2.1 Stack\r\n\r\nstack（栈）实现了Vector类，后进先出。\r\n\r\n#### 1.1.3 LinkedList\r\n```java\r\npublic class LinkedList<E>\r\n    extends AbstractSequentialList<E>\r\n    implements List<E>, Deque<E>, Cloneable, java.io.Serializable\r\n```\r\n\r\n实现List接口，Deque接口；基于链式的存储方式\r\n\r\n### 1.2 Queue\r\nqueue用于模拟队列这种数据结构，先进先出。\r\n#### 1.2.1PriorityQueue\r\n\r\n最大堆，最小堆，基于数据的完全二叉树实现\r\n\r\n#### 1.2.2 Deque\r\n\r\n##### 1.2.2.1 LinkedList\r\n\r\n实现了List和Deque（双端队列Deque继承了Queue接口）两个接口。它可以作为List和Queue使用，也可以作为栈进行使用。\r\n\r\n### 1.3 Set\r\nSet继承Collection接口，不能包含重复元素，Set判断两个对象不是使用==来判断，是使用equals方法，新加入的元素会与已有的元素判断equals比较返回false则加入，否则拒绝加入；所以使用Set的时候有两点需要注意：1.放入的对象要实现equals方法；2.对set的构造函数中，传入的Collection参数不能包含重复的元素。\r\n\r\n#### 1.3.1 HashSet\r\n\r\nHashSet实现了Set接口，由哈希表提供支持，不保证Set的迭代顺序；允许使用null值，同时不允许元素有重复，因为HashSet底层是使用HashMap来实现的，HashSet中的元素都存放在HashMap的key上面，value是一个统一的静态变量；\r\n\r\nHashSet中添加元素调用add方法，然后会调用HashMap的put方法插入元素，HashMap的put方法插入元素时，会首先判断是否存在key，如果不存在，则插入这个key-value,存在则修改value值；在set中，value值没用，因此往HashSet中添加元素，首先判断key是否存在，不存在插入元素，存在则不做处理；\r\nHashSet使用Hash算法存储集合中的元素，具有很好的查找和存取性能。向HashSet中存入一个元素时，HashSet调用对象的HashCode方法获取对象的HashCode值，根据HashCode值决定对象的存储位置。HashSet判断元素对象是否相同的方法是同时使用HashCode和equals方法来判断，关于equals方法和HashCode的说明：\r\n\r\n1.equals相等的对象，hashCode一定相等；\r\n\r\n2.equals不相等的对象，hashCode可能相等，也可能相等。（哈希生成的时候产生碰撞）\r\n\r\n3.反之，HashCode不相等，则equals方法一定不相等（如果equals相等则与规则1矛盾）；\r\n\r\n4.HashCode相等，equals可以相等，也可以不相等。\r\n\r\nHashSet判断元素相等方法时，首先判断两个对象的HashCode是否相等，如果不相等，则认为两个对象也不相等，如果相等再判断equals方法是否相等；如果hashCode相等，equals方法不相等，则认为时不同的对象；为什么这样做，主要是为了提高效率，HashCode的效率比equals效率更高，不必每次重新计算Hash值.\r\n##### 1.3.1.1 linkedHashSet\r\nlinkedHashSet继承自HashSet，同时使用链表来维护元素的顺序，元素以插入的顺序进行访问；在性能上略低于HashSet,但在迭代访问时有很好的性能；\r\n\r\n#### 1.3.2 SortedSet\r\n主要用于排序操作，实现此接口的子类都属于排序子类。\r\n\r\n##### 1.3.2.1 TreeSet\r\n基于SortedSet，底层实现是通过二叉树，插入的元素要实现Comparable接口。','15.jpg',1,'0',NULL,0,0,'Y'),(14,'Git的安装和使用','Git（分布式版本管理），我们在项目开发的过程中通常是团队协作完成的，在这个过程中，我们会用到版本控制管理工具，例如：SVN Git CVS等。\r\nSVN托管网站需要我们拥有一个（版本库）中央仓库，并且需要每一个工作站与中央仓库网络互通才能进行访问。而Git中没有一个中央仓库的概念，每一个工作站拥有一个本地版本库(分支)，用户将修改后的代码存放到本地版本库中，开发过程中不需要依赖网络环境，只是在最终合并的时候将工作站中的所有版本库进行推送合并到服务器版本库（master）。','hairui623968','2020-04-23','2020-04-23 11:09:28',NULL,'# Git安装和使用\r\n\r\n### 1.Git（分布式版本管理）简述\r\n我们在项目开发的过程中通常是团队协作完成的，在这个过程中，我们会用到版本控制管理工具，例如：SVN Git CVS等。\r\nSVN托管网站需要我们拥有一个（版本库）中央仓库，并且需要每一个工作站与中央仓库网络互通才能进行访问。而Git中没有一个中央仓库的概念，每一个工作站拥有一个本地版本库(分支)，用户将修改后的代码存放到本地版本库中，开发过程中不需要依赖网络环境，只是在最终合并的时候将工作站中的所有版本库进行推送合并到服务器版本库（master）。\r\n### 2.Git工作原理：\r\n本地工作目录提交到暂存区，当代码达到一定量后最终提交到服务器版本库。\r\n本地工作目录 -> 暂存区：git add\r\n暂存区 -> 版本库：git commit\r\n本地计算机工作目录 推送到 其他计算机工作目录：git push\r\n其他计算机工作目录 拉取到 本地计算机工作目录：git pull\r\n### 3.Git的安装\r\n下载地址：[msysgit.github.io](msysgit.github.io \"msysgit.github.io\") 会根据自己当前用户的操作系统类型重定向到相应的下载页面\r\n![](/myblog/upload/17ae46c1-7c1b-4e79-b40e-e65be171022e.png)\r\n![](/myblog/upload/d177a90b-5657-47f8-bfac-4255b9168561.png)\r\n\r\n下载完成后打开，选择默认配置进行安装。\r\n安装完成后进入cmd下确认输入：git --version 查看是否已经将git添加到环境变量中（2.19默认自动将git添加到环境变量中），如果没有添加，则需要在path中添加git命令执行路径，例如：D:\\Program Files\\Git\\cmd\r\n![](/myblog/upload/905d8a09-82ab-4fcd-b32b-9661e7b17a27.png)\r\n### 4.Git的本地配置\r\n打开git bash，配置用户名和邮箱,用户名和邮箱相当于SVN中的用户名密码，是区分用户的唯一标识符，输入如下命令：\r\ngit config --global user.name \"example\"\r\ngit config --global user.email \'example@163.com\'\r\n添加完成后可以使用：git config --list 来查看配置是否生效，也可以在本地用户目录下查看.gitconfig文件中的内容与配置是否一致。\r\n![](/myblog/upload/7a8f815d-ebab-454c-8461-5a52c7ce405a.png)\r\n### 5.配置远程仓库\r\n登录[https://github.com](https://github.com \"https://github.com\")，新建仓库\r\n![](/myblog/upload/9cbd55b6-5dc9-4c6b-bc90-34e3d2276c57.png)\r\n添加仓库名称：demo 添加描述：初始化demo版本\r\n![](/myblog/upload/b5bf9067-80f4-4de8-9e5e-3947ebfc8c24.png)\r\n对应的https地址：[https://github.com/hairuizone/demo.git](https://github.com/hairuizone/demo.git \"https://github.com/hairuizone/demo.git\")\r\n对应的ssh地址：git@github.com:hairuizone/demo.git\r\n此时远程仓库已经配置完成。\r\n### 6.配置本地免密登录服务器仓库\r\n目的：本地计算机与远程服务器之间进行通信关联\r\n本地打开git bash，输入：ssh-keygen -t rsa -C example@163.com\r\n将密钥创建到本地用户目录下\r\n![](/myblog/upload/2d4e4e5d-fca8-45b5-9478-ea7650a2b043.png)\r\n将本地公钥添加到服务器：\r\n    使用记事本打开id_rsa.pub，并将内容拷贝。\r\n    打开github服务器，选择Settings，并选择如图操作创建新的SSH key\r\n![](/myblog/upload/3a369503-410b-4449-9ce3-5bfc01fbe575.png)\r\nTitle：任意名称\r\nKey：将刚才拷贝的密钥粘贴进来，**并将最后的回车删除**\r\n![](/myblog/upload/0b7dadaa-6c6f-47fd-9351-b248cc125603.png)\r\n此时，已经将本地的ssh公钥添加到服务器端，可以使用如下命令验证免密钥登录是否成功：\r\nssh -T git@github.com 提示输入：yes 出现如下界面说明免密登录已经配置完成。同时本地用户目录文件下可以看到一个known_hosts的文件。\r\n![](/myblog/upload/ef530b23-aad6-4005-84f4-0a545d4ded67.png)\r\n### 7.创建Git案例项目\r\n 在本地创建git项目\r\nD盘新建文件夹：gitdemo\r\n在此文件夹下创建文件helloGit.txt \r\nhelloGit.txt内容如下：hello this is git\r\n在项目根目录（gitdemo文件夹内）右键 Git Bash Here\r\n输入git init，完成后可以看到当前目录下出现了.git文件夹 则说明git本地项目创建成功。\r\n![](/myblog/upload/cf13950e-c767-471e-9fb8-b76f6f512a0b.png)\r\n![](/myblog/upload/2d86f897-6113-46d3-a6ba-d6c51cdd9b5f.png)\r\n### 8.本地项目与远程资源库进行关联\r\ngit remote add origin https://github.com/hairuizone/demo.git\r\n或者使用ssh唯一标识符进行关联\r\ngit remote add origin git@github.com:hairuizone/demo.git\r\n![](/myblog/upload/f7374af1-a44e-41a4-b664-8d315ed30a87.png)\r\n### 9.Git常见命令的使用\r\n#### 第一次发布项目\r\n将本地项目发布到服务器\r\n将本地项目提交到暂存区：git add .\r\n暂存区推到本地分支：git commit -m \"注释内容\"\r\n第一次将本地分支提交到远程仓库：git push -u origin master\r\n![](/myblog/upload/07c3d612-1a95-46dc-99ec-c7052887f927.png)\r\n登录服务器查看查看刚才提交的内容如下：\r\n![](/myblog/upload/c71fc487-ab06-45f3-af7b-1f41e681b586.png)\r\n#### 第一次下载项目\r\n    远程下载到本地：git clone https://github.com/hairuizone/demo.git\r\n#### 提交项目\r\n    我们将hellGit.txt中的文件进行修改：hello this is git 1234，然后进行提交。\r\ngit add .\r\ngit commit -m \"注释\"\r\ngit push origin master\r\n![](/myblog/upload/b2dc2983-d5f5-4bbe-8768-08d790e748d3.png)\r\n![](/myblog/upload/1f6d3af3-9ad0-4a51-b4cf-6e25a1ca111a.png)\r\n#### 更新项目\r\n远程更新到本地\r\ngit pull\r\n','17.jpg',6,'0',NULL,2,0,'Y'),(15,'基于Springboot开发属于自己的博客','基于Springboot开发属于自己的博客','hairui623968','2020-04-23','2020-05-08 12:14:11',NULL,'## 开发目的\r\n\r\n针对于目前比较流行个springboot框架，以学习为目的，开发了一套属于自己的个人博客系统，用于记录自己在平时工作中遇到的一些问题，以及对自己学习的一些知识点进行了总结归纳。\r\n\r\n## 功能需求\r\n\r\n### 页面元素\r\n\r\n网站页面主要包含三部分元素：导航、正文、底部。\r\n\r\n导航：展示站点中的主要功能模块，包含首页、分类、标签、归档、个人信息、友情链接和登录查询操作按钮。\r\n\r\n正文：根据所在页面不同展示相应的结果。\r\n\r\n底部：网站的基础信息，这里将底部设计为“个人微信二维码”，“邮箱和QQ联系信息”，“网站备注说明信息”\r\n\r\n### 页面详细设计\r\n\r\n#### 首页\r\n\r\n**导航栏内容：**\r\n\r\n游客访问：首页 分类 标签 归档 关于我 友链\r\n\r\n登录用户：首页 分类 标签 归档 <font color=red>我的空间</font> 关于我 友链\r\n\r\n**正文内容：**\r\n\r\n  - 左边展示区\r\n    - 占比：11/16\r\n    - 内容：系统收录博客数量；博客 ：标题、简介、作者头像、作者、浏览量、发布时间、所属分类、封面图；分页元素。\r\n  - 右边展示区\r\n    - 占比：5/16\r\n    - 内容：网站信息、分类、标签、最新推荐、本章信息、传送门、公众号二维码\r\n\r\n**底部footer**\r\n\r\n我的二维码、联系我、站点说明\r\n\r\n#### 分类\r\n\r\n- 左边展示区\r\n  - 分类名称、分类下的文章数量，选中后变色；分页元素\r\n- 右边展示区\r\n  - 标签、最新推荐、本章信息、传送门、公众号二维码\r\n\r\n#### 标签\r\n\r\n- 左边展示区\r\n  - 标签名称、标签下的文章数量，选中后变色；分页元素\r\n- 右边展示区\r\n  - 分类、最新推荐、本章信息、传送门、公众号二维码\r\n\r\n#### 归档\r\n\r\n- 左边展示区\r\n  - 年份；文章数量；文章标题、发布时间、查看次数、点赞次数、原创标志；分页元素\r\n- 右边展示区\r\n  - 分类、标签、最新推荐、本章信息、传送门、公众号二维码\r\n\r\n#### 我的空间\r\n\r\n暂无内容\r\n\r\n#### 关于我\r\n\r\n- 左边展示区\r\n  - 照片\r\n- 右边展示区\r\n  - 网站名片、关于我、爱好、技能\r\n\r\n#### 友情链接\r\n\r\n- 左边展示区 12/16\r\n  - 好友博客；大佬博客；学习网站\r\n- 右边展示区 4/12\r\n  - 网站名片、分类标签、最新推荐、本章信息、传送门、公众号二维码\r\n\r\n### 表结构设计\r\n\r\n#### 相册表（album）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    album\r\n    (\r\n        ID INT(10) unsigned NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        NAME VARCHAR(256) COMMENT \'名称\',\r\n        SHOW_IMG VARCHAR(256) COMMENT \'封面图\',\r\n        SHOW_FLAG VARCHAR(8) COMMENT \'是否展示\',\r\n        INTRODUCTION VARCHAR(1024) COMMENT \'介绍\',\r\n        CREATE_TIME VARCHAR(32) COMMENT \'创建时间\',\r\n        CREATOR VARCHAR(32) COMMENT \'创建人\',\r\n        LOCATION VARCHAR(256) COMMENT \'地点\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'相册表\';\r\n```\r\n\r\n\r\n\r\n#### 相册照片表（albumimg）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    albumimg\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        ALBUM_ID INT NOT NULL COMMENT \'相册编号\',\r\n        IMG_NAME VARCHAR(256) COMMENT \'照片名称\',\r\n        IMG_PATH VARCHAR(256) COMMENT \'照片路径\',\r\n        INTRODUCTION VARCHAR(1024) COMMENT \'介绍\',\r\n        ADD_TIME VARCHAR(32) COMMENT \'添加时间\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'相册照片表\';\r\n```\r\n\r\n#### 文章表（artical）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    artical\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        TITLE VARCHAR(256) COMMENT \'标题\',\r\n        SUMMARY VARCHAR(1024) COMMENT \'摘要\',\r\n        CREATE_ID VARCHAR(32) COMMENT \'创建人\',\r\n        CREATE_DATE VARCHAR(32) COMMENT \'创建日期\',\r\n        CREATE_TIME VARCHAR(32) COMMENT \'创建时间\',\r\n        UPDATE_TIME VARCHAR(32) COMMENT \'更新时间\',\r\n        CONTENT longtext COMMENT \'内容\',\r\n        INDEX_PICTURE VARCHAR(256) COMMENT \'首页图片\',\r\n        TYPE_ID INT COMMENT \'分类\',\r\n        REPRINT_FLAG VARCHAR(8) COMMENT \'是否转载\',\r\n        REPRINT_URL VARCHAR(256) COMMENT \'转载地址\',\r\n        VIEW_TIMES INT COMMENT \'查看次数\',\r\n        LIKE_TIMES INT COMMENT \'点赞次数\',\r\n        SHOW_FLAG VARCHAR(8) COMMENT \'是否公开\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin;\r\n```\r\n\r\n#### 文章标签关联表（articaltag）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    articaltag\r\n    (\r\n        ARTICAL_ID INT NOT NULL COMMENT \'文章编号\',\r\n        TAG_ID INT NOT NULL COMMENT \'标签编号\',\r\n        PRIMARY KEY (ARTICAL_ID, TAG_ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'文章标签关联表\';\r\n```\r\n\r\n#### 点赞记录表（likerecord）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    likerecord\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        LIKE_DATE VARCHAR(32) NOT NULL COMMENT \'访问日期\',\r\n        IP_ADDRESS VARCHAR(32) NOT NULL COMMENT \'IP地址\',\r\n        ARTICAL_ID INT NOT NULL COMMENT \'文章编号\',\r\n        LAST_LIKE_TIME VARCHAR(32) COMMENT \'最近一次点赞时间\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'点赞记录表\';\r\n```\r\n\r\n\r\n\r\n#### 友情链接表（link）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    link\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        WEBNAME VARCHAR(32) COMMENT \'网站名称\',\r\n        MOTTO VARCHAR(256) COMMENT \'介绍\',\r\n        URL VARCHAR(256) COMMENT \'网站地址\',\r\n        WEBICON VARCHAR(256) COMMENT \'网站图标\',\r\n        WEBMASTER VARCHAR(32) COMMENT \'站长姓名\',\r\n        WECHAT VARCHAR(32) COMMENT \'微信号\',\r\n        PHONE VARCHAR(32) COMMENT \'站长手机号\',\r\n        EMAIL VARCHAR(32) COMMENT \'站长邮箱\',\r\n        TYPE VARCHAR(8) COMMENT \'分类\',\r\n        STATUS VARCHAR(8) COMMENT \'状态\',\r\n        CREATETIME VARCHAR(32) COMMENT \'创建时间\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'友情链接表\';\r\n```\r\n\r\n#### 留言表（MESSAGE）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    MESSAGE\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'消息编号\',\r\n        ARTICAL_ID INT COMMENT \'文章编号\',\r\n        ACCOUNT VARCHAR(32) COMMENT \'用户名\',\r\n        CONTENT VARCHAR(1024) COMMENT \'留言内容\',\r\n        MESSAGE_TIME VARCHAR(32) COMMENT \'留言时间\',\r\n        STATUS VARCHAR(8) COMMENT \'状态\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'留言表\';\r\n```\r\n\r\n\r\n\r\n#### 留言回复表（messagereply）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    messagereply\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT,\r\n        MSGID INT COMMENT \'消息编号\',\r\n        FROMACCOUNT VARCHAR(32) COMMENT \'发消息用户\',\r\n        TOACCOUNT VARCHAR(32) COMMENT \'收消息用户\',\r\n        CONTENT VARCHAR(1024) COMMENT \'留言内容\',\r\n        REPLYTIME VARCHAR(32) COMMENT \'回复时间\',\r\n        STATUS VARCHAR(8) COMMENT \'状态\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'留言回复表\';\r\n```\r\n\r\n\r\n\r\n#### 我的信息表（myinfo）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    myinfo\r\n    (\r\n        ID INT NOT NULL COMMENT \'编号\',\r\n        NICKNAME VARCHAR(32) COMMENT \'网名\',\r\n        NAME VARCHAR(32) COMMENT \'站长姓名\',\r\n        WEBNAME VARCHAR(32) COMMENT \'网站名称\',\r\n        OCCUPATION VARCHAR(32) COMMENT \'职业\',\r\n        ADDRESS VARCHAR(256) COMMENT \'地址\',\r\n        EMAIL VARCHAR(256) COMMENT \'邮箱\',\r\n        WEBSITE VARCHAR(256) COMMENT \'网址\',\r\n        QQ VARCHAR(32) COMMENT \'QQ号码\',\r\n        WECHAT VARCHAR(32) COMMENT \'微信号\',\r\n        WEBICON VARCHAR(32) COMMENT \'网站图标\',\r\n        MOTTO VARCHAR(256) COMMENT \'座右铭\',\r\n        PROPHOTO VARCHAR(32) COMMENT \'头像\',\r\n        GITEE VARCHAR(256) COMMENT \'gitee\',\r\n        GITHUB VARCHAR(256) COMMENT \'github\',\r\n        WEIBO VARCHAR(256) COMMENT \'新浪微博\',\r\n        BRANDIMG VARCHAR(32) COMMENT \'网站LOGO\',\r\n        RECORD VARCHAR(256) COMMENT \'备案号\',\r\n        CREATETIME VARCHAR(32) COMMENT \'创建时间\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'我的信息表\';\r\n```\r\n\r\n\r\n\r\n#### 重置密码记录表（resetpwdlog）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    resetpwdlog\r\n    (\r\n        ACCOUNT VARCHAR(32) NOT NULL COMMENT \'帐号\',\r\n        TOKEN VARCHAR(256) NOT NULL COMMENT \'token码\',\r\n        EMAIL VARCHAR(32) COMMENT \'邮箱\',\r\n        SUBMIT_TIME VARCHAR(32) COMMENT \'提交时间\',\r\n        PRIMARY KEY (ACCOUNT)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'重置密码记录表\';\r\n```\r\n\r\n#### 资源表（s_resc_manage）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    s_resc_manage\r\n    (\r\n        RESC_ICON VARCHAR(32) COMMENT \'资源图标\',\r\n        RESC_NAME VARCHAR(32) COMMENT \'资源名称\',\r\n        RESC_ID VARCHAR(32) NOT NULL COMMENT \'资源编号\',\r\n        ORDER_ID INT NOT NULL COMMENT \'排序编号\',\r\n        USE_FLAG VARCHAR(8) COMMENT \'使用标志 on off\',\r\n        PRIMARY KEY (RESC_ID, ORDER_ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'资源表\';\r\n```\r\n\r\n#### 菜单表（s_resc_menu）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    s_resc_menu\r\n    (\r\n        TARGET VARCHAR(32) COMMENT \'目标地\',\r\n        SPREAD TINYINT(1) COMMENT \'是否展开 true false\',\r\n        HREF VARCHAR(200) NOT NULL COMMENT \'链接地址\',\r\n        ICON VARCHAR(8) COMMENT \'菜单图标\',\r\n        TITLE VARCHAR(32) COMMENT \'名称\',\r\n        RESC_ID VARCHAR(32) NOT NULL COMMENT \'资源编号\',\r\n        ORDER_ID INT COMMENT \'排序编号\',\r\n        USE_FLAG VARCHAR(8) COMMENT \'使用标志 on off\',\r\n        PRIMARY KEY (HREF, RESC_ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'菜单表\';\r\n```\r\n\r\n#### 标签表（tag）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    tag\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        NAME VARCHAR(32) COMMENT \'标签名称\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'标签表\';\r\n```\r\n\r\n#### 分类表（type）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    type\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        NAME VARCHAR(32) COMMENT \'分类名称\',\r\n        SHOW_FLAG VARCHAR(8) COMMENT \'是否展示\',\r\n        INTRODUCTION VARCHAR(1024) COMMENT \'介绍\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'分类表\';\r\n```\r\n\r\n#### 用户表（USER）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    USER\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        ACCOUNT VARCHAR(32) COMMENT \'帐号\',\r\n        PASSWORD VARCHAR(256) COMMENT \'密码\',\r\n        NICKNAME VARCHAR(32) COMMENT \'昵称\',\r\n        SEX VARCHAR(8) COMMENT \'性别\',\r\n        AGE INT COMMENT \'年龄\',\r\n        NAME VARCHAR(32) COMMENT \'真实姓名\',\r\n        PROPHOTO VARCHAR(32) COMMENT \'头像\',\r\n        EMAIL VARCHAR(32) COMMENT \'邮箱\',\r\n        MOBILE VARCHAR(32) COMMENT \'手机号\',\r\n        TYPE VARCHAR(8) COMMENT \'用户类型\',\r\n        CREATE_TIME VARCHAR(32) COMMENT \'创建时间\',\r\n        UPDATE_TIME VARCHAR(32) COMMENT \'更新时间\',\r\n        STATUS VARCHAR(8) COMMENT \'用户状态\',\r\n        LAST_LOGIN_TIME VARCHAR(32) COMMENT \'上次登录时间\',\r\n        ERROR_COUNT INT,\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'用户信息表\';\r\n```\r\n\r\n#### 文章查看记录表（viewrecord）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    viewrecord\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        VISIT_DATE VARCHAR(32) NOT NULL COMMENT \'访问日期\',\r\n        IP_ADDRESS VARCHAR(32) NOT NULL COMMENT \'IP地址\',\r\n        ARTICAL_ID INT NOT NULL COMMENT \'文章编号\',\r\n        LAST_VISIT_TIME VARCHAR(32) COMMENT \'最近一次访问时间\',\r\n        VISIT_COUNT INT COMMENT \'访问次数\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'文章查看记录表\';\r\n```\r\n\r\n#### 网站访问记录表（visitrecord）\r\n\r\n```mysql\r\nCREATE TABLE\r\n    visitrecord\r\n    (\r\n        ID INT NOT NULL AUTO_INCREMENT COMMENT \'编号\',\r\n        VISIT_DATE VARCHAR(32) NOT NULL COMMENT \'访问日期\',\r\n        IP_ADDRESS VARCHAR(32) COMMENT \'IP地址\',\r\n        LAST_VISIT_TIME VARCHAR(32) COMMENT \'最近访问时间\',\r\n        VISIT_COUNT INT COMMENT \'访问次数\',\r\n        PRIMARY KEY (ID)\r\n    )\r\n    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin COMMENT=\'网站访问记录表\';\r\n```\r\n\r\n## 逻辑功能\r\n\r\n#### 角色设定\r\n\r\n- 普通游客：可以访问网站中公开的内容，比如公开的文章，公开的分类\r\n- 注册用户：可以访问\"我的空间模块\",可以设置自己的文章是否公开，可以设置自己的个性化信息。\r\n- 管理员：可以管理系统中的文章、分类、标签等，可以编辑站点信息，管理用户。向所有用户发送消息。\r\n- 黑名单IP用户：禁止访问本网站（暂未实现）\r\n\r\n#### 逻辑说明\r\n\r\n##### 前端\r\n\r\n- 游客登录情况下，展示所有网站中公开的内容。\r\n- 用户登录情况下，展示公开的内容以及自己名下创建的内容（目前还未实现用户自己创建内容功能，只有通过赋予管理员的权限后实现）。\r\n- 管理员登录后展示网站中所有的内容。\r\n\r\n##### 后端\r\n\r\n- 分类管理：分类下存在文章不允许删除\r\n- 标签管理：标签下存在文章不允许删除\r\n- 文章管理：管理员可以对已经发布的文章进行删除\r\n- 相册管理：管理员可以创建相册，创建相册后可以将照片放入到相册中。如果相册中有照片，则无法直接对相册进行删除操作，必须先删除照片，再删除相册。\r\n- 用户管理：对用户进行解锁、锁定和查看资料操作。\r\n- 导航菜单管理：设置网站头部的访问菜单元素信息。\r\n- 功能菜单管理：根据编码内容设定菜单所属的导航菜单，同时设置菜单的操作。\r\n- 网站配置中心：网站的系统参数配置，用户展示给用户网站的整个轮廓信息。\r\n\r\n\r\n\r\n## 开发技术\r\n\r\n### 前端\r\n\r\n前端页面UI：semanticUI\r\n\r\n前端框架：thymeleaf\r\n\r\n文章内容的编写和查看：markdown editmd组件进行编写。 \r\n\r\n管理端：layui框架。\r\n\r\n### 后端\r\n\r\n后台开发框架：springboot springMVC mybits mybits-plus\r\n\r\n数据库：mysql\r\n\r\n分页组件：pagehelper\r\n\r\nJDK：1.8\r\n\r\n数据源管理组件：Druid\r\n','22.jpg',1,'0',NULL,6,1,'Y'),(16,'Springboot项目中logback配置文件示例','logback介绍：基于Log4j基础上大量改良，不能单独使用，推荐配合日志框架SLF4J来使用，可以和springboot很好的整合，也是springboot默认推荐的。','hairui623968','2020-04-24','2020-04-24 14:38:56',NULL,'> logback介绍：基于Log4j基础上大量改良，不能单独使用，推荐配合日志框架SLF4J来使用，可以和springboot很好的整合，也是springboot默认推荐的。\r\n\r\n\r\n### logback配置\r\n**需要的依赖**\r\n```xml\r\n<dependency>\r\n  <groupId>org.springframework.boot</groupId>\r\n  <artifactId>spring-boot-starter-logging</artifactId>\r\n</dependency>\r\n```\r\n<font color=red>实际开发中我们不需要直接添加该依赖，你会发现spring-boot-starter其中包含了\r\nspring-boot-starter-logging，该依赖内容就是 Spring Boot 默认的日志框架 logback。</font>\r\n\r\n**logback-spring.xml(名字可以自己定义，官方推荐叫这个所以我就叫这个)**\r\n```xml\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<configuration scan=\"true\" scanPeriod=\"60 seconds\" debug=\"false\">\r\n    <contextName>logback</contextName>\r\n    <property name=\"log.path\" value=\"C:/mblog/log/\"/>\r\n    <!--输出到控制台-->\r\n    <appender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\r\n        <!--此日志appender是为开发使用，只配置最底级别，控制台输出的日志级别是大于或等于此级别的日志信息-->\r\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\r\n            <level>debug</level>\r\n        </filter>\r\n        <encoder>\r\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>\r\n            <charset>utf-8</charset>\r\n        </encoder>\r\n    </appender>\r\n\r\n    <!--输出到debug-->\r\n    <appender name=\"debug\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <fileNamePattern>${log.path}/logback-debug-%d{yyyy-MM-dd}.log</fileNamePattern>\r\n        </rollingPolicy>\r\n        <append>true</append>\r\n        <encoder>\r\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>\r\n            <charset>utf-8</charset>\r\n        </encoder>\r\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\"><!-- 只打印DEBUG日志 -->\r\n            <level>DEBUG</level>\r\n            <onMatch>ACCEPT</onMatch>\r\n            <onMismatch>DENY</onMismatch>\r\n        </filter>\r\n    </appender>\r\n    <!--输出到info-->\r\n    <appender name=\"info\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <fileNamePattern>${log.path}/logback-info-%d{yyyy-MM-dd}.log</fileNamePattern>\r\n        </rollingPolicy>\r\n        <append>true</append>\r\n        <encoder>\r\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>\r\n            <charset>utf-8</charset>\r\n        </encoder>\r\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\"><!-- 只打印INFO日志 -->\r\n            <level>INFO</level>\r\n            <onMatch>ACCEPT</onMatch>\r\n            <onMismatch>DENY</onMismatch>\r\n        </filter>\r\n    </appender>\r\n\r\n    <!--输出到error-->\r\n    <appender name=\"error\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <fileNamePattern>${log.path}/logback-error-%d{yyyy-MM-dd}.log</fileNamePattern>\r\n        </rollingPolicy>\r\n        <append>true</append>\r\n        <encoder>\r\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>\r\n            <charset>utf-8</charset>\r\n        </encoder>\r\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\"><!-- 只打印ERROR日志 -->\r\n            <level>ERROR</level>\r\n            <onMatch>ACCEPT</onMatch>\r\n            <onMismatch>DENY</onMismatch>\r\n        </filter>\r\n    </appender>\r\n\r\n    <!--输出到warn-->\r\n    <appender name=\"warn\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <fileNamePattern>${log.path}/logback-warn-%d{yyyy-MM-dd}.log</fileNamePattern>\r\n        </rollingPolicy>\r\n        <append>true</append>\r\n        <encoder>\r\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>\r\n            <charset>utf-8</charset>\r\n        </encoder>\r\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\"><!-- 只打印WARN日志 -->\r\n            <level>WARN</level>\r\n            <onMatch>ACCEPT</onMatch>\r\n            <onMismatch>DENY</onMismatch>\r\n        </filter>\r\n    </appender>\r\n    <!--用户统计-->\r\n    <appender name=\"dataApp\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <fileNamePattern>${log.path}/logback-data-%d{yyyy-MM-dd}.log</fileNamePattern>\r\n        </rollingPolicy>\r\n        <append>true</append>\r\n        <encoder>\r\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>\r\n            <charset>utf-8</charset>\r\n        </encoder>\r\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\"><!-- 只打印INFO日志 -->\r\n            <level>INFO</level>\r\n            <onMatch>ACCEPT</onMatch>\r\n            <onMismatch>DENY</onMismatch>\r\n        </filter>\r\n    </appender>\r\n    <!--用于统计数据 比如某个方法执行了多少次-->\r\n    <logger name=\"dataLogger\">\r\n        <level value=\"INFO\"/>\r\n        <appender-ref ref=\"dataApp\"/>\r\n    </logger>\r\n\r\n\r\n    <!--开发环境:打印控制台-->\r\n    <springProfile name=\"dev\">\r\n        <!--<logger name=\"com.phfund\" level=\"debug\"/>-->\r\n        <root level=\"DEBUG\">\r\n            <appender-ref ref=\"console\"/>\r\n            <appender-ref ref=\"debug\"/>\r\n            <appender-ref ref=\"info\"/>\r\n            <appender-ref ref=\"error\"/>\r\n            <appender-ref ref=\"warn\"/>\r\n        </root>\r\n    </springProfile>\r\n\r\n    <!--生产环境:输出到文件-->\r\n    <springProfile name=\"prd\">\r\n        <root level=\"INFO\">\r\n            <appender-ref ref=\"console\"/>\r\n            <appender-ref ref=\"debug\"/>\r\n            <appender-ref ref=\"info\"/>\r\n            <appender-ref ref=\"error\"/>\r\n            <appender-ref ref=\"warn\"/>\r\n        </root>\r\n    </springProfile>\r\n\r\n</configuration>\r\n```\r\n\r\n**使用示例**\r\n```java\r\n//在需要打日志的地方，类下面加上。\r\nprivate Logger logger = LoggerFactory.getLogger(this.getClass());\r\n//用于统计使用，一般项目小项目不用可忽略\r\nprivate Logger dataLogger = LoggerFactory.getLogger(\"dataLogger\");\r\n在方法上里加：\r\n//这个数据会保存到统计信息的日志文件中去。\r\ndataLogger.info(\"module=video_order \'api=save\'user_id={}\'video_id={}\",videoOrderDto.getUserId(),videoOrderDto.getVideoId());\r\n//正常的日志记录\r\nlogger.info(\"module=video_order\'api=save\'user_id={}\'video_id={}\",videoOrderDto.getUserId(),videoOrderDto.getVideoId());\r\n```\r\n','27.jpg',4,'0',NULL,4,1,'Y'),(17,'这谁写的代码，连个注释都没有','这谁写的代码，连个注释都没有','hairui623968','2020-04-26','2020-04-26 13:11:23',NULL,'![](/upload/artical/0049B128631E4CD0ACCE3357635FE8F4.jpg)','19.jpg',6,'0',NULL,9,1,'Y'),(18,'Java常用方法大全','本文主要是对日常开发过程中遇到的一些常用的java方法进行了整理，以便于后期使用的时候直接翻阅，提高开发效率，减少不必要的代码编写，内容会不断完善补充。','hairui623968','2020-04-25','2020-04-25 13:15:06',NULL,'### Date相关\r\n**获取当前时间，格式yyyy-MM-dd**\r\n```java\r\npublic static String getCurrentDate() {\r\n    Date date = new Date();\r\n    DateFormat df = new SimpleDateFormat(\"yyyy-MM-dd\");\r\n    return df.format(date);\r\n}\r\n```\r\n\r\n**获取当前时间 格式：yyyy-MM-dd HH&#58;mm&#58;ss**\r\n```java\r\npublic static String getCurrentTime() {\r\n    Date date = new Date();\r\n    DateFormat df = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\r\n    return df.format(date);\r\n}\r\n```','30.jpg',1,'0',NULL,24,1,'Y'),(19,'我35岁，工作13年，明天退休','很多人眼中，程序员都是秃头吧。\r\n正是因为长期对着电脑、熬夜上线，程序员这个高薪的职业不仅费脑，更费头发，最重要的是伤身体。\r\n2020年对待程序员更残酷了一些，降薪、裁员、失业…这个春天，俨如寒冬。','hairui623968','2020-04-30','2020-04-30 13:11:45',NULL,'很多人眼中，程序员都是秃头吧。\r\n\r\n正是因为长期对着电脑、熬夜上线，程序员这个高薪的职业不仅费脑，更费头发，最重要的是伤身体。\r\n\r\n2020年对待程序员更残酷了一些，降薪、裁员、失业…这个春天，俨如寒冬。\r\n\r\n我们也不得不寻求加班机会，才能够保证收入。伤害身体不说，还可能会影响我们的情感生活。\r\n\r\n这是民政局发布的一组扎心离婚数据。\r\n\r\n![近9年结婚、离婚数据](/upload/artical/D64A8A5EF656461DB8554F23C8E8E495.jpg \"近9年结婚、离婚数据\")\r\n\r\n可以看出，9年来，**结婚率在下降，但离婚率却在持续增高。**\r\n\r\n甚至，更有某机构统计：在中国离婚最多的城市，离婚率竟然高达39%。\r\n\r\n也就是说，**每10对新人结婚，就有将近4对夫妇离婚**！\r\n\r\n不过也不难想象，两人结婚后，风花雪月变成了柴米酱醋，容易忽视对方的感受，缺少了当初的那份体贴，开始忙碌地经营家庭生活。\r\n\r\n![](/upload/artical/FF2302AEED5F440C82F56DD48E9CEE1F.jpg)\r\n\r\n上周大学聚会，遇见了多年不见的朋友艳子，大家聊到各自结婚后的生活 。\r\n\r\n艳子的老公是一个对她温柔体贴的普通男人。\r\n\r\n恋爱三年修成正果，一直是大家心中的真爱模范。结婚后，房贷和车贷却让原本就不富裕的日子捉襟见肘。\r\n\r\n艳子压抑着自己，不敢买贵的化妆品和衣服，不能参加太多朋友聚会，能省则省；老公则是更加的忙碌了。\r\n\r\n夫妻之间沟通逐渐变少，终日忙忙碌碌，本身因为爱组成的家庭，昔日的浪漫和爱意在日常生活中消磨殆尽。\r\n\r\n有孩子之后，每天早起送儿子上学，工作一天回家后，无论再累也得给儿子补习功课，晚上的夫妻生活？两人都已经累得没有了想法，甚至连话都不怎么说。\r\n\r\n艳子说，真的，我们结婚6年，自己并不是后悔和他结婚，而是现在的生活压得她喘不过气……\r\n\r\n![](/upload/artical/226B88BDC797400E99E8C24978F1B44E.gif)\r\n\r\n我看着她说，但大多数人，何尝不是这样的呢？\r\n\r\n人人都想有尊严的活着，然而现实是残酷的：\r\n\r\n结婚前刚毕业，拿着几千的工资需要交房租，日常开销，孝敬父母，生活入不敷出。\r\n\r\n结婚以后，房贷车贷，出门旅游，参加同学同事婚礼，买些化妆品和衣服，压力如牛负重。\r\n\r\n有了宝宝，压力更大。孩子的衣物玩具，辅导班、兴趣班，一个都不能少。\r\n\r\n父母年老后，生一场大病，足以把一个家庭击垮。\r\n\r\n![](/upload/artical/60799830A0E946DAAB9A2D55518884A0.gif)\r\n\r\n生活本不易，且行且珍惜。','10.jpg',10,'1','https://mp.weixin.qq.com/s/17DICif71tZpjlVzM7Egig',3,0,'Y'),(20,'Oracle Sql 性能优化调整','选用适合的Oracle优化器，Oracle的优化器共有3种：Rule（基于规则）Cost（基于成本）Choose（选择性）\r\n设置缺省的优化器，可以通过对init.ora文件中的Optimizer_mode参数的各种声明，如Rule,Cost,Choose,All_rows,First_rows。你当然也在Sql句级或是会话（Session）级对其进行覆盖。\r\n','hairui623968','2020-05-09','2020-05-09 12:05:59',NULL,'## Oracle Sql 性能优化调整\r\n\r\n### 一、选用适合的Oracle优化器，Oracle的优化器共有3种：\r\n\r\nØ Rule（基于规则）\r\n\r\nØ Cost（基于成本）\r\n\r\nØ Choose（选择性）\r\n\r\n设置缺省的优化器，可以通过对init.ora文件中的Optimizer_mode参数的各种声明，如Rule,Cost,Choose,All_rows,First_rows。你当然也在Sql句级或是会话（Session）级对其进行覆盖。\r\n\r\n为了使用基于成本的优化器（CBO,Cost-Based Optimizer），你必须经常运行Analyze命令，以增加数据库中的对象统计信息（Object statistics）的准确性。\r\n\r\n如果数据库的优化器模式设置为选择性（Choose），那么实际的优化器模式将和是否运行过Analyze命令有关。如果table已经被analyze过，优化器模式将自动成为CBO，反之，数据库将采用Rule形式的优化器。\r\n\r\n在缺省情况下，Oracle采用Choose优化器，为了避免那些不必要的全表扫描（Full table scan），你必须尽量避免使用Choose优化器，而直接采用基于规则或者基于成本的优化器。\r\n\r\n### 二、访问Table的方式，Oracle采用两种访问表中记录的方式\r\n\r\nØ 全表扫描\r\n\r\n全表扫描就是顺序地访问表中每条记录。Oracle采用一次读入多个数据块(database block)的方式优化全表扫描。\r\n\r\nØ 通过Rowid访问表\r\n\r\n你可以采用基于Rowid的访问方式情况，提高访问表的效率，Rowid包含了表中记录的物理位置信息……Oracle采用索引(index)实现了数据和存放数据的物理位置（Rowid）之间的联系。通常索引提供了快速访问Rowid的方法，因此那些基于索引列的查询就可以得到性能上的提高。\r\n\r\n### 三、共享SQL语句\r\n\r\n为了不重复解析相同的SQL语句，在第一次解析之后，Oracle将SQL语句存放在内存中。这块位于系统全局区域SGA(system global area)的共享池（shared buffer pool）中的内存可以被所有的数据库用户共享。因此，当你执行一个SQL语句（有时被称为一个游标）时，如果它和之前的执行过的语句完全相同，Oracle就能很快获得已经被解析的语句以及最好的执行路径。Oracle的这个功能大大地提高了SQL的执行性能并节省了内存的使用。\r\n\r\n可惜的是Oracle只对简单的表提供高速缓冲(cache buffering)，这个功能并不适用于多表连接查询。\r\n\r\n数据库管理员必须在init.ora中为这个区域设置合适的参数，当这个内存区域越大，就可以保留更多的语句，当然被共享的可能性也就越大了。\r\n\r\n当你向Oracle提交一个SQL语句，Oracle会首先在这块内存中查找相同的语句。\r\n\r\n这里需要注明的是，Oracle对两者采取的是一种严格匹配，要达成共享，SQL语句必须完全相同（包括空格，换行等）\r\n\r\n共享的语句必须满足三个条件：\r\n\r\nØ 字符级的比较\r\n\r\n当前被执行的语句和共享池中的语句必须完全相同。例如：\r\n\r\nSELECT * FROM EMP; 和下列每一个都不同\r\n\r\nSELECT * from EMP;\r\n\r\nSelect * From Emp;\r\n\r\nSELECT  *  FROM EMP;\r\n\r\nØ 两个语句所指的对象必须完全相同\r\n\r\n例如：\r\n\r\n| 用户 | 对象名       | 如何访问        |\r\n| ---- | ------------ | --------------- |\r\n| Jack | sal_limit    | private synonym |\r\n|      | Work_city    | public synonym  |\r\n|      | Plant_detail | public synonym  |\r\n| Jill | sal_limit    | private synonym |\r\n|      | Work_city    | public synonym  |\r\n|      | Plant_detail | table owner     |\r\n\r\n考虑一下下列SQL语句能否在这两个用户之间共享\r\n\r\n| SQL                                                          | 能否共享 | 原因                                                         |\r\n| ------------------------------------------------------------ | -------- | ------------------------------------------------------------ |\r\n| Select max(sal_cap) from sal_limit;                          | 不能     | 每个用户都有一个private synonym – sal_limit，它们是不同的对象 |\r\n| Select count(*) from work_city where  sdesc like ‘NEW%’      | 能       | 两个用户访问相同的对象public synonym – work_city             |\r\n| Select a.sdesc,b.location from Work_city a, plant_detail b where a.city_id = b.city_id | 不能     | 用户jack通过private synonym访问plant_detail 而Jill是表的所有者，对象不同 |\r\n\r\nØ 两个SQL语句中必须使用相同的名字的绑定变量(bind variables)\r\n\r\n例如：第一组的两个SQL语句是相同的（可以共享），而第二组中的两个语句是不同的（即使在运行时，赋于不同的绑定变量相同的值）\r\n\r\na.\r\n\r\n```\r\nselect pin , name from people where pin = : blk1.pin;\r\n\r\nselect pin , name from people where pin = : blk1.pin;\r\n```\r\n\r\nb.\r\n\r\n```\r\nselect pin , name from people where pin = : blk1.ot_ind;\r\n\r\nselect pin , name from people where pin = : blk1.ov_ind;\r\n```\r\n\r\n### 四、选择最有效的表名顺序（只在基于规则的优化器中有效）\r\n\r\nOracle的解析器按照从右到左的顺序处理From子句中的表名，因此From子句中写在最后的表（基础表driving table）将被最先处理。在From子句中包含多个表的情况下，你必须选择记录条数最少的表作为基础表。当Oracle处理多个表时，会运用排序及合并的方式连接它们。首先，扫描第一个表（From子句中最后的那个表）并对记录进行派序，然后扫描第二个表（From子句中最后第二个表），最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并。\r\n\r\n例如： 表TAB1 16，384 条记录\r\n\r\n	表TAB2 1条记录\r\n\r\n选择TAB2作为基础表（最好的方法）\r\n\r\nSelect count(*) from tab1,tab2; 执行时间0.96秒\r\n\r\n选择TAB1作为基础表（不佳的方法）\r\n\r\nSelect count(*) from tab2,tab1; 执行时间26.09秒\r\n\r\n如果有3个以上的表连接查询，那就需要选择交叉表(intersection table)作为基础表，交叉表是指那个被其他表所引用的表。\r\n\r\n例如：EMP表描述了Location表和Category表的交集。\r\n\r\n```sql\r\nselect *\r\n	from Location l, Category c, EMP E\r\n	where E.EMP_NO Between 1000 and 2000\r\n	and E.CAT_NO = c.CAT_NO\r\nand E.LOCN = L.LOCN\r\n```\r\n\r\n将比下列SQL更有效率\r\n\r\n```sql\r\nselect *\r\n	from EMP E , Location l , Category c\r\n	where E.CAT_NO = c.CAT_NO\r\n	and E.LOCN = L.LOCN\r\nand E.EMP_NO Between 1000 and 2000\r\n```\r\n\r\n### 五、Where子句中的连接顺序\r\n\r\nOracle采用自下而上的顺序解析Where子句，根据这个原理，表之间的连接必须写在其他Where条件之前，那些可以过滤掉最大数量记录的条件必须写在Where子句的末尾。\r\n\r\n例如：\r\n\r\n```sql\r\nselect ...\r\n	from EMP E\r\n	where SAL>50000 and JOB =\'MANAGER\'\r\n	and 25 < (select count(*) from EMP where MGR = E.EMPNO)\r\n```\r\n\r\n（低效，执行时间156.3秒）\r\n\r\n```sql\r\nselect ...\r\n	from EMP E\r\n	where 25 < (select count(*) from EMP where MGR = E.EMPNO)\r\n	 and SAL > 50000 and JOB = \'MANAGER\'\r\n```\r\n（高效，执行时间10.6秒）\r\n\r\n### 六、Select子句中避免使用’*’\r\n\r\n当你想在Select子句中列出所有的Column时，使用动态SQL列引用’*’是一个方便的方法。不幸的是，这是一个非常低效的方法。实际上，Oracle在解析的过程中，会将’*’依次转换成所有的列名，这个工作是通过查询数据字典完成的，这意味着将耗费更多的时间。\r\n\r\n### 七、减少访问数据库的次数\r\n\r\n当执行每条SQL语句时，Oracle在内部执行了许多工作：解析SQL语句，估算索引的利用率，绑定变量，读数据块等等。由此可见，减少访问数据库的次数，就能实际上减少Oracle的工作量。\r\n\r\n例如：以下有三种方法可以检索出雇员号等于0342或0291的职员。\r\n\r\nØ 方法1（最低效）\r\n\r\n```sql\r\nselect EMP_NAME, SALARY, GRADE \r\nfrom EMP \r\nwhere EMP_NO = 0342\r\n\r\nselect EMP_NAME, SALARY, GRADE \r\nfrom EMP \r\nwhere EMP_NO = 0291\r\n```\r\n\r\nØ 方法2（次低效）\r\n\r\n```sql\r\ndeclare\r\ncursor c1(E_NO NUMBER) is\r\nselect EMP_NAME, SALARY, GRADE from EMP Where EMP_NO = E_NO;\r\nBegin\r\n	Open c1(0342);\r\n	fetch c1\r\n	into …, .., ..;\r\n	Open c1(0291);\r\n	fetch c1\r\n	into …, .., ..;\r\n	close c1;\r\nend;\r\n```\r\n\r\nØ 方法3（高效）\r\n\r\n```sql\r\nselect a.EMP_NAME, a.SALARY, a.GRADE, \r\n	b.EMP_NAME, b.SALARY, b.GRADE\r\n	from \r\n		EMP a, EMP b\r\n	where \r\n		a.EMP_NO = 0342\r\n		and b.EMP_NO = 0291;\r\n```\r\n\r\n	注意：\r\n\r\n	在SQL*Plus,SQL*Forms和Pro*C中重新设置Arraysize参数，可以增加每次数据库访问的检索数据量，建议值为200。\r\n\r\n### 八、使用Decode函数来减少处理时间\r\n\r\n使用Decode函数可以避免重复扫描相同记录或重复连接相同的表\r\n\r\n例如：\r\n\r\n```\r\nselect count(*), sum(sal)\r\n	from EMP\r\n	where DEPT_NO = 0020\r\n	and ENAME LIKE \'SMITH%\';\r\n	\r\nselect count(*), sum(sal)\r\n	from EMP\r\n	where DEPT_NO = 0030\r\nand ENAME LIKE \'SMITH%\';\r\n```\r\n\r\n你可以用Decode函数高效地得到相同结果\r\n```\r\nselect count(decode(dept_no, 0020, \'X\', Null)) D0020_count,\r\n	count(decode(dept_no, 0030, \'X\', Null)) D0030_count,\r\n	sum(decode(dept_no, 0020, sal, null)) D0020_sal,\r\n	sum(decode(dept_no, 0030, sal, null)) D0030_sal\r\n	from EMP\r\nwhere Ename like \'SMITH%\'\r\n```\r\n\r\n类似的，Decode函数也可以运用于Group By和Order By子句中。\r\n\r\n### 九、整合简单，无关联的数据库访问\r\n\r\n如果你有几个简单的数据库查询语句，你可以把它们整合到一个查询中（即使它们之间没有关系）\r\n\r\n例如：\r\n\r\n```\r\nselect name from EMP where EMP_no = 1234;\r\nselect name from DTP where DPT - no = 10;\r\nselect name from CAT where CAT_type = \'RD\';\r\n```\r\n\r\n上面的3个查询可以被合并成一个：\r\n\r\n```sql\r\nselect E.name, D.name, C.name\r\n	from CAT C, DPT D, EMP E, DUAL X\r\n	where NVL(\'X\', X.DUMMY) = NVL(\'X\', E.Rowid(+))\r\n	and NVL(\'X\', X.DUMMY) = NVL(\'X\', D.Rowid(+))\r\n	and NVL(\'X\', X.DUMMY) = NVL(\'X\', C.Rowid(+))\r\n	and E.EMP_NO(+) = 1234\r\n	and D.DEPT_NO(+) = 10\r\nand C.CAT_TYPE(+) = \'RD\'\r\n```\r\n（译者按：虽然采用这种方法，效率得到提高，但是程序的可读性大大降低，所以读者还是要权衡之间的利弊）\r\n\r\n### 十、删除重复记录\r\n\r\n最高效的删除重复记录方法（因为使用了Rowid）\r\n```sql\r\ndelete from EMP E\r\n	where E.Rowid > (select min(x.rowid) \r\n	from EMP X \r\nwhere X.EMP_NO = E.EMP_NO);\r\n```\r\n\r\n### 十一、用Truncate替代Delete\r\n\r\n当删除表中的记录时，在通常情况下，回滚段（rollback segments）用来存放可以被恢复的信息。如果你没有Commit事务，Oracle会将数据恢复到删除之前的状态（准确地说是恢复到执行删除命令之前的状况）\r\n而当运用Truncate时，回滚段不再存放任何可被恢复的信息。当命令运行后，数据不能被恢复。因此很少的资源被调用，执行时间也会很短。\r\n\r\n（译者按：Truncate只在删除全表适用，Truncate是DDL不是DML）\r\n\r\n### 十二、尽量多使用Commit\r\n\r\n只要有可能，在程序中尽量多使用Commit，这样程序的性能得到提高，需求也会因为Commit所释放的资源而减少。Commit所释放的资源：\r\n\r\nØ 回滚段上用于恢复数据的信息\r\nØ 被程序语句获得的锁\r\nØ Redo log buffer中的空间\r\nØ Oracle为管理上述3种资源中的内部花费\r\n\r\n（译者按：在使用Commit时必须要注意到事务的完整性，现实中效率和事务完整性往往是鱼和熊掌不可兼得）\r\n\r\n### 十三、计算记录条数\r\n和一般的观点相反，count(*)比count(1)稍快，当然如果可以通过索引检索，对索引列的计数仍旧是最快的。如：count(empno)\r\n\r\n(译者按：在CSDN论坛中，曾经对此有过相当热烈的讨论，作者的观点并不十分准确，通过实际的测试，上述三种访求并没有显著的性能差别)\r\n\r\n### 十四、用Where子句替换Having子句\r\n避免使用Having子句，Having只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序，总计等操作。如果能通过Where子句限制记录的数目，那就能减少这方面的开销。\r\n例如：\r\n```\r\nselect region, avg(log_size)\r\n	from location\r\n	group by region\r\nhaving region region != \'sydney\' and region != \'perth\'\r\n```\r\n（低效）\r\n```\r\nselect region, avg(log_size)\r\n	from location\r\n	where region region != \'sydney\' and region != \'perth\'\r\ngroup by region\r\n```\r\n（高效）\r\n（译者按：Having中的条件一般用于对一些集合函数的比较，如count()等等。除此而外，一般的条件应该写在Where子句中）\r\n### 十五、减少对表的查询\r\n在含有子查询的SQL语句中，要特别注意减少对表的查询。\r\n例如：\r\n```\r\nselect tab_name\r\n	from tables\r\n	where tab_name = (select tab_name \r\n		from tab_columns \r\n			where version = 604)\r\n			and db_ver = (select db_ver \r\n		from tab_columns \r\n			where version = 604);\r\n```\r\n   （低效）\r\n```\r\nselect tab_name\r\n	from tables\r\n	where (tab_name, db_ver) =\r\n		(select tab_name, db_ver \r\n		from tab_columns \r\n		where version = 604);\r\n```\r\n  （高效）\r\nUpdate多个Column例子：\r\n```\r\nupdate EMP\r\n	set EMP_CAT  = (select max(category) from EMP_Categories),\r\n	sal_range = (select max(sal_range) from EMP_Categories)\r\nwhere EMP_Detp = 0020;\r\n```\r\n（低效）\r\n```\r\nupdate EMP\r\n	set (EMP_CAT, SAL_RANGE) = (Select max(category), max(sal_range)\r\n	from EMP_Categories)\r\nwhere EMP_Dept = 0020;\r\n```\r\n（高效）\r\n### 十六、通过内部函数提高SQL效率\r\n```sql\r\nselect h.empno, e.ename, h.hist_type, t.type_desc, count(*)\r\n	from history_type t, emp e, emp_history h\r\n	where h.empno = e.empno\r\n	and h.hist_type = t.hist_type\r\ngroup by h.empno, e.ename, h.hist_type, t.type_desc;\r\n```\r\n通过调用下面的函数可以提高效率\r\n```sql\r\nfunction lookup_hist_type(typ in number) return varchar2 as\r\n	tdesc varchar2(30);\r\n	cursor c1 is\r\n	select type_desc from history_type where hist_type = typ;\r\nbegin\r\n	open c1;\r\n	fetch c1\r\n	into tdesc;\r\n	close c1;\r\n	return(nvl(tdesc, \'?\'));\r\nend;\r\n```\r\n```sql\r\nfunction lookup_emp(typ in number) return varchar2 as\r\n	tdesc varchar2(30);\r\n	cursor c1 is\r\n	select ename from emp where empno = emp;\r\nbegin\r\n	open c1;\r\n	fetch c1\r\n	into ename;\r\n	close c1;\r\n	return(nvl(ename, \'?\'));\r\nend;\r\n```\r\n```sql\r\nselect h.empno,\r\n	lookup_emp(h.empno),\r\n	h.hist_type,\r\n	lookup_hist_type(h.hist_type),\r\n		count(*)\r\n	from emp_history h\r\ngroup by h.empno, h.hist_type;\r\n```\r\n\r\n（译者按：经常在论坛中看到如“能不能用一个SQL写出…。”的帖子，殊不知复杂的SQL往往牺牲了执行效率。能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的）\r\n\r\n### 十七、使用表的别名（Alias）\r\n\r\n当在SQL语句中连接多个表时，请使用表的别名并把别名前缀于每个Column上。这样一来，就可以减少解析的时间并减少那些由Column歧义引起的语法错误。\r\n\r\n（译者注：Column歧义指的是由于SQL中不同的表具有相同的Column名，当SQL语句中出现这个Column时，SQL解析器无法判断这个Column的归属）\r\n\r\n### 十八、用Exists替代In\r\n\r\n在许多基于基础表的查询中，为了满足一个条件，往往需要对另一个表进行联接。在这种情况下，使用Exists（或Not Exists）通常将提高查询的效率。\r\n\r\n```sql\r\nselect *\r\n	from emp(基础表)\r\n   where empno > 0\r\nand deptno in (select deptno from dept where loc = \'MELB\')\r\n```\r\n\r\n（低效）\r\n\r\n```sql\r\nselect *\r\n   from emp(基础表)\r\n   where empno > 0\r\n	and exists (select \'X\'\r\n	     from dept\r\n	     where dept.deptno = emp.deptno\r\nand loc = \'MELB\')\r\n```\r\n（高效）\r\n（译者按：相对来说，用Not Exists替换Not in将更显著地提高效率，下一节中将指出）\r\n### 十九、用Not Exists替代Not In\r\n在子查询中，Not In子句将执行一个内部的排序和合并。无论在哪种情况下，Not In都是最低效的（因为它对子查询中的表执行了一个全表遍历）。为了避免使用Not In，我们可以把它改写成外连接（Outer Joins）或Not Exists。\r\n例如：\r\n\r\n```sql\r\nselect ...\r\n   from emp\r\n   where dept_no not in (select dept_no \r\n	           from dept \r\nwhere dept_cat = \'A\');\r\n```\r\n为了提高效率。改写为：\r\n（方法一：高效）\r\n```sql\r\nselect ...\r\n   from emp a, dept b\r\n   where a.dept_no = b.dept(+)\r\n	 and b.dept_no is null\r\nand b.dept_cat(+) = \'A\';\r\n```\r\n（方法二：最高效）\r\n```sql\r\nselect ...\r\n   from emp e\r\n   where not exists (select \'X\'\r\n	        from dept d\r\n	        where d.dept_no = e.dept_no\r\nand dept - cat = \'A\');\r\n```\r\n### 二十、用表连接替换Exists\r\n通常来说，采用表连接的方式比Exists更有效率\r\n```sql\r\nselect ename\r\n   from emp e\r\n   where exists (select \'X\'\r\n	     from dept\r\n	     where dept_no = e.dept_no\r\n	    and dept_cat = \'A\');\r\n```\r\n（更高效）\r\n```sql\r\nselect ename\r\n   from dept d, emp e\r\n   where e.dept_no = d.dept_no\r\n  and dept_cat = \'A\';\r\n```\r\n（译者按：在RBO的情况下，前者的执行路径包括Filter，后者使用Nested Loop）\r\n### 二十一、用Exists替换Distinct\r\n当提交一个包含一对多表信息（比如部门表和雇员表）的查询时，避免在Select子句中使用Distinct。一般可以考虑用Exist替换。\r\n例如：\r\n低效：\r\n```sql\r\nselect distinct dept_no, dept_name\r\n   from dept d, emp e\r\nwhere d.dept_no = e.dept_no;\r\n```\r\n高效：\r\n```sql\r\nselect dept_no, dept_name\r\n   from dept d\r\n   where exists (select \'X\'\r\n	      from emp e\r\nwhere e.dept_no = d.dept_no);\r\n```\r\nExists使查询更为迅速，因为Rdbms核心模块将在子查询的条件一旦满足后，立刻返回结果。\r\n### 二十二、识别“低效执行”的SQL语句\r\n用下列SQL工具找出低效SQL：\r\n```sql\r\nselect executions,\r\n	disk_reads,\r\n	buffer_gets,\r\n	round((buffer_gets - disk_reads) / buffer_gets, 2) hit_radio,\r\n	round(disk_reads / executions, 2) reads_per_run,\r\n	SQL_text\r\n   from V$sqlarea\r\n   where executions > 0\r\n	and buffer_gets > 0\r\n	and (buffer_gets - disk_reads) / buffer_gets < 0.8\r\norder by 4 desc;\r\n```\r\n（译者按：虽然目前各种关于SQL优化的图形化工具导出不穷，但是写出自己的SQL工具来解决问题始终是一个最好的方法）\r\n### 二十三、使用Tkprof工具来查询SQL性能状态\r\nSQL trace工具收集正在执行的SQL的性能状态数据并记录到一个跟踪文件中。这个跟踪文件提供了许多有用的信息，例如：解析次数。执行次数，CPU使用时间等。这些数据将可以用来优化你的系统。\r\n设置SQL trace在会话级别：\r\n有效\r\nalter session set sql_trace true\r\n设置SQL trace在整个数据库有效仿，你必须将SQL_trace参数在init.ora中设为True，User_dump_dest参数说明了生成跟踪文件的目录。\r\n（译者按：这一节中，作者并没有提到Tkprof的用法，对SQL Trace的用法也不够准确，设置SQL Trace首先要在init.ora中设定Timed_statistics，这样才能得到那些重要的时间状态。生成的trace文件是不可读的，所以要用Tkprof工具对其进行转换，Tkprof有许多执行参数。大家可以参考Oracle手册来了解具体的配置。）\r\n### 二十四、用Explain Plan分析SQL语句\r\nExplain Plan是一个很好的分析SQL语句的工具，它甚至可以在不执行SQL的情况下分析语句。通过分析，我们就可以知道Oracle是怎么样连接表，使用什么方式扫描表（索引扫描或全表扫描）以及使用到的索引名称。\r\n你需要按照从里到外，从上到下的次序解读分析的结果。Explain Plan分析的结果是用缩进的格式排列的，最内部的操作将被最先解读，如果两个操作处于同一层中，带有最小操作号的将被首先执行。\r\n\r\nNested Loop是少数不按照上述规则处理的操作，正确的执行路径是检查对Nested Loop提供数据的操作，其中操作号最小的将被最先处理。\r\n\r\n（译者按：通过实践，感到还是用Sqlplus中的Set trace功能比较方便。）\r\n例如：\r\nSQL> list\r\n```sql\r\nselect *\r\n	from dept,emp\r\nwhere emp.deptno = dept.deptno\r\n```\r\nSQL> set autotrace traceonly\r\ntraceonly可以不显示执行结果\r\n\r\nSQL>\r\n14 rows selected.\r\nExecution Plan\r\n\\-------------------------------------------------------\r\n0    select stratement Optimizer = CHOOSE\r\n1   0 Nested Loops\r\n2   1  Table Access (full) of ‘EMP’\r\n3   2  Table Access (BY Index Rowid) of ‘Dept’\r\n4   3  Index (Unique Scan) of ‘Pk_dept’ (Unique)\r\n\r\nStatistics\r\n  0 recursive calls\r\n  2 db block gets\r\n 30 consistent gets\r\n  0 physical reads\r\n  0 redo size\r\n2598 bytes sent via SQL*Net to client\r\n 503 bytes received via SQL*Net from client\r\n  2 SQL*Net roundtrips to/from client\r\n  0 sorts (memory)\r\n  0 sorts (disk)\r\n 14 rows processed\r\n\r\n通过以上分析，可以得出实际的执行步骤是：\r\n1．     Table access (full) of ‘emp’\r\n2．     Index (unique Scan) of ‘Pk_dept’ (Unique)\r\n3．     Table access (by Index rowid) of ‘dept’\r\n4．     Nested Loops (Joining 1 and 3)\r\n注：目前许多第三方的工具如Toad和Oracle本身提供的工具如OMS的SQL Analyze都提供了极其方便的Explain Plan工具。也许喜欢图形化界面的朋友们可以用它们。\r\n### 二十五、用索引提高效率\r\n索引是表的一个概念部分，用来提高检索数据的效率。实际上，Oracle使用了一个复杂的自平衡B-tree结构。通常，通过索引查询数据比全表扫描要快。当Oracle找出执行查询和Update语句的最佳路径时，Oracle优化器将使用索引。同样在联结多个表时使用索引也可以提高效率。另一个使用索引的好处是，它提供了主键（primary key）的唯一性验证。\r\n\r\n除了那些Long或Long Raw数据类型，你可以索引几乎所有的列。通常，在大型表中使用索引特别有效。当然，你也会发现，在扫描小表时，使用索引同样能提高效率。\r\n\r\n虽然使用索引能得到查询效率的提高，但是我们也必须注意到它的代价。索引需要空间来存储，也需要定期维护，每当有记录在表中增减或索引列被修改时，索引本身也会被修改。这意味着每条记录的Insert,Delete,Update将为此多付出4，5次的磁盘I/O。因为索引需要额外的存储空间和处理，那些不必要的索引反而会使查询反应时间变慢。\r\n\r\n（译者按：定期的重构索引是有必要的。\r\nAlter index <Indexname> rebuild <Tablespacename>）\r\n### 二十六、索引的操作\r\nOracle对索引有两访问模式\r\nØ 索引唯一扫描（Index Unique Scan）\r\n大多数情况下，优化器通过Where子句访问Index\r\n例如：\r\n表Lodging有两个索引：建立在Lodging列上的唯一性索引Lodging_PK和建立在Manager列上的非唯一性索引Lodging$Manager.\r\n\r\n```sql\r\nSelect *\r\n	from Lodging\r\n	Where Loging = ‘rose hill’;\r\n```\r\n\r\n在内部，上述SQL将被分成两步执行，首先，Lodging_PK索引将通过索引唯一扫描的方式被访问，获得相对应的Rowid，通过Rowid访问表的方式执行下一步检索。\r\n\r\n如果被检索返回的列包括在Index列中，Oracle将不执行第二步的处理（通过Rowid访问表）。因为检索数据保存在索引中，单单访问索引就可以完全满足查询结果。\r\n\r\n下面SQL只需要Index Unique Scan操作。\r\n```sql\r\nSelect lodging\r\n	from lodging\r\nwhere lodging = ‘rose hill’;\r\n```\r\nØ 索引范围查询（Index Range Scan）\r\n\r\n适用于两种情况：基于一个范围的检索；基于非唯一性索引的检索。\r\n\r\n例1：\r\n```sql\r\nSelect lodging \r\n	from lodging\r\nwhere lodging like ‘m%’;\r\n```\r\nWhere子句条件包括一系列值，Oracle将通过索引范围查询的方式查询Lodging_pk.由于索引范围查询将返回一组值，它的效率就要比索引唯一扫描低一些。\r\n\r\n例2：\r\n```sql\r\nSelect lodging\r\n	from lodging\r\nwhere manager = ‘bill gates’;\r\n```\r\n这个SQL的执行分两步，Lodging$Manager的索引范围查询（得到所有符合条件记录的Rowid）和下一步通过Rowid访问表得到Lodging列的值。由于Lodging$Manager是一个非唯一性的索引，数据库不能对它执行索引唯一扫描。\r\n\r\n由于SQL返回Lodging列，而它并不存在于Lodging$Manager索引中，所以在索引范围查询后会执行一个通过Rowid访问表的操作。\r\nWhere子句中，如果索引列所对应的值的第一个字符由通配符（Wildcard）开始，索引将不被采用。在这种情况下，Oracle将使用全表扫描。\r\n```sql\r\nSelect lodging\r\n	from lodging\r\nwhere manager like ‘%hanman’;\r\n```\r\n### 二十七、基础表的选择\r\n基础表（Driving Table）是指被最先访问的表（通常以全表扫描的方式被访问）。根据优化器的不同，SQL语句中基础表的选择是不一样的。\r\n如果你使用的是CBO(Cost Based Optimizer)，优化器会检查SQL语句中的每个表的物理大小，索引状态，然后选用花费最低的执行路径。\r\n\r\n如果你用RBO(Rule Based Optimizer)，并且所有的连接条件都有索引对应，在这种情况下，基础表就是From子句中列在最后的那个表。\r\n\r\n例如：\r\n```sql\r\nSelect a.name,b.manager\r\n	from worker a, lodging b\r\nwhere a.lodging = b.loding;\r\n```\r\n由于Lodging表的Loding列上有一个索引，而且Worker表中没有相比较的索引，Worker表将被作为查询中的基础表。\r\n### 二十八、多个平等的索引\r\n当SQL语句的执行路径可以使用分布在多个表上的多个索引时，Oracle会同时使用多个索引并在运行时对它们的记录进行合并，检索出仅对全部索引有效的记录。\r\n\r\n在Oracle选择执行路径时，唯一性索引的等级高于非唯一性索引。然而这个规则只有当Where子句中索引列和常量比较才有效。如果索引列和其他表的索引类相比较。这种子句在优化器中的等级是非常低的。\r\n\r\n如果不同表中两个相同等级的索引将被引用，From子句中表的顺序将决定哪个会被率先使用。From子句中最后的表的索引将有最高的优先级。\r\n如果相同表中两个相同等级的索引将被引用，Where子句中最先被引用的索引将有最高的优先级。\r\n例如：\r\nDeptno上有一个非唯一性索引，EMP_cat也有一个非唯一性索引。\r\n```sql\r\nSelect ename\r\nfrom emp\r\nwhere deptno = 20\r\nand emp_cat = ‘A’;\r\n```\r\n这里，Deptno索引将被最先检索，然后同EMP_Cat索引检索出的记录进行合并。执行路径如下：\r\nTable access by rowid on emp\r\nAnd-equal\r\n\r\n Index range scan on dept_Idx\r\n\r\n Index range scan on cat_Idx\r\n\r\n### 二十九、等式比较和范围比较\r\n\r\n当Where子句中有索引列，Oracle不能合并它们，Oracle将用范围比较。\r\n例如：\r\nDeptno上有一个非唯一性索引，Emp_Cat也有一个非唯一性索引。\r\n```sql\r\nSelect ename\r\nfrom emp\r\nwhere deptno > 20\r\nand emp_cat = ‘A’;\r\n```\r\n这里只有Emp_cat索引被用到，然后所有的记录将逐条与Deptno条件进行比较。执行路径如下：\r\nTable access by rowid on emp\r\nIndex range scan on cat_idx\r\n### 三十、不明确的索引等级\r\n当Oracle无法判断索引的等级高低差别，优化器将只使用一个索引，它就是在Where子句中被列在最前面的。\r\n例如：\r\nDeptno上有一个非唯一性索引，Emp_cat也有一个非唯一性索引。\r\n```sql\r\nSelect ename\r\nfrom emp\r\nwhere deptno > 20\r\nand emp_cat > ‘A’;\r\n```\r\n这里，Oracle只用到Dept_no索引。执行路径如下：\r\nTable access by rowid on emp\r\nIndex range scan on dept_idx\r\n\r\n  (译者按：我们来试一下以下这种情况：)\r\n\r\nSQL> select index_name,uniqueness from user_indexes where table_name = ‘emp’;\r\nIndex_name      Uniquenes\r\n\\-------------------------------------------------\r\nEMPNO        UNIQUE\r\nEMPTYPE       NONUNIQUE\r\nSQL> select * from emp where empno >= 2 and emp_type = ‘A’;\r\nNo rows selected\r\nExecution Plan\r\n\\-------------------------------------------------\r\n\r\n0    Select statement Optimizer=CHOOSE\r\n1   0 Table access (by index rowid) of ‘emp’\r\n2   1  Index (range scan) of ‘emptype’ (non-unique)\r\n虽然Empno是唯一性索引，但是由于它所做的是范围比较，等级要比非唯一性索引的等式比较低！\r\n### 三十一、强制索引失败\r\n\r\n如果两个或以上索引具有相同的等级，你可以强制命令Oracle优化器使用其中一个（通过它，检索出的记录数量少）。\r\n\r\n例如：\r\nSelect ename\r\nfrom emp\r\nwhere empno = 7935\r\nand deptno + 0 = 10 /*deptno上的索引将失败*/\r\nand emp_type || ‘’= ‘A’/*emp_type上的索引将失效*/\r\n\r\n这是一种相当直接的提高查询效率的办法。但是你必须谨慎考虑这种策略，一般来说，只有在你希望单独优化几个SQL时才能采用它。\r\n\r\n这里有一个例子关于何时采用这种策略，\r\n\r\n假设在Emp表的Emp_type列上有一个非唯一性的索引而Emp_class上没有索引。\r\n\r\n```sql\r\nSelect ename\r\nfrom emp\r\nwhere emp_type = ‘A’\r\nand emp_class = ‘X’;\r\n```\r\n\r\n优化器会注意到Emp_type上的索引并使用它。这是目前唯一的选择。如果，一段时间以后，另一个非唯一性建立在Emp_class上，优化器必须对两个索引进行选择,在通常情况下，优化器将使用两个索引并在他们的结果集合上执行排序及合并。然而，如果其中一个索引（Emp_type）接近于唯一性而另一个索引（Emp_class）上有几千个重复的值。排序及合并就会成为一种不必要的负担。在这种情况下，你希望使优化器屏蔽掉Emp_class索引。\r\n\r\n用下面的方案就可以解决问题。\r\n```sql\r\n\r\nSelect ename\r\nfrom emp\r\nwhere emp_type = ‘A’\r\nand emp_class || ‘’= ‘X’;\r\n```\r\n### 三十二、避免在索引列上使用计算\r\nWhere子句中，如果索引列是函数的一部分。优化器将不使用索引而使用全表扫描。\r\n\r\n例如：\r\n(低效)\r\n```sql\r\nSelect …\r\nfrom dept\r\nwhere sal * 12 > 25000;\r\n```\r\n（高效）\r\n```sql\r\nSelect …\r\nfrom dept\r\nwhere sal > 25000/12;\r\n```\r\n\r\n译者按：这是一个非常实用的规则，请务必牢记。\r\n\r\n### 三十三、自动选择索引\r\n\r\n如果表中有两个以上（包括两个）索引，其中有一个唯一性索引，而其他是非唯一性。\r\n\r\n在这种情况下，Oracle将使用唯一性索引而完全忽略非唯一性索引。\r\n\r\n例如：\r\n\r\n```sql\r\nSelect ename\r\nfrom emp\r\nwhere empno=2326\r\nand deptno=20;\r\n```\r\n\r\n这里，只有Empno上的索引是唯一性的，所以Empno索引将用来检索记录。\r\n\r\nTable access by rowid on emp\r\n\r\nIndex unique scan on emp_no_idx\r\n\r\n### 三十四、避免在索引列上使用Not\r\n\r\n通常我们要避免在索引列上使用Not，Not会产生和在索引列上使用函数相同的影响。当Oracle“遇到”Not，他就会停止使用索引转而执行全表扫描。\r\n\r\n例如：\r\n低效（这里不使用索引）\r\n```sql\r\nSelect …\r\nfrom dept\r\nwhere dept_code not = 0;\r\n```\r\n高效（这里使用索引）\r\n```sql\r\nSelect …\r\nfrom dept\r\nwhere dept_code > 0;\r\n```\r\n需要注意的是，在某些时候，Oracle优化器会自动将Not转化成相对应的关系操作符。\r\nNot > to <=\r\nNot >= to <\r\nNot < to >=\r\nNot <= to >\r\n译者按：在这个例子中，作者犯了一些错误。例子中的低效率SQL是不能被执行的。我做了一些测试。\r\n\r\nSQL> select * from emp where Not empno >1;\r\nNo rows selected\r\nExecution Plan\r\n\r\n\\-----------------------------------------------------\r\n0    Select Statement Optimizer=CHOOSE\r\n1   0 Table Access (by index rowid) of ‘emp’\r\n2   1  Index (range scan) of ‘empno’ (unique)\r\nSQL> select * from emp where empno <=1;\r\nNo rows selected\r\nExecution Plan\r\n\r\n\\-----------------------------------------------------\r\n0    select statement optimizer=shoose\r\n1   0 table access (by index rowid) of ‘emp’\r\n2   1  index (range scan) of ‘empno’ (unique)\r\n\r\n两者的效率完全一样，也许这符合作者关于“在某些时候，Oracle优化器会自动将Not转化成相对应的关系操作符”的观点。\r\n### 三十五、用>=替代>\r\n如果Deptno上有一个索引。\r\n高效：\r\n```sql\r\nSelect *\r\nfrom emp\r\nwhere deptno >=4;\r\n```\r\n低效：\r\n```sql\r\nSelect *\r\nfrom emp\r\nwhere deptno >3;\r\n```\r\n\r\n两者的区别在于，前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到Deptno=3的记录并且向前扫描到第一个DEPT大于3的记录。\r\n\r\n### 三十六、用Union替换Or（适用于索引列）\r\n\r\n通常情况下，用Union替换Where子句中的Or将会起到较好的效果。对索引列使用Or将造成全表扫描。注意，以上规则只针对多个索引列有效。如果有Column没有被索引，查询效率可能会因为你没有选择Or而降低。\r\n\r\n在下面的例子中，Loc_id和Region上都建有索引。\r\n高效：\r\n```sql\r\nSelect loc_id,loc_desc,region\r\nfrom location\r\nwhere loc_id = 10\r\nunion\r\nSelect loc_id,loc_desc,region\r\nfrom location\r\nwhere region = ‘Melbourne’;\r\n```\r\n\r\n低效：\r\n```sql\r\nSelect loc_id,loc_desc,region\r\nfrom location\r\nwhere loc_id = 10 or region = ‘Melbourne’;\r\n```\r\n如果你坚持要用Or，那就需要返回记录最少的索引列写在最前面。\r\n\r\n注意：\r\nWhere key1 = 10 (返回最少记录)\r\nOr key2 = 20 (返回最多记录)\r\nOracle内部将以上转换为\r\nWhere key1 = 10 and ((not key1 = 10) and key2 = 20)\r\n译者按：\r\n\r\n下面的测试数据仅供参考：（a=1003返回一条记录，b=1返回1003条记录）\r\n\r\nSQL> select * from unionvsor 1st test\r\n2 where a = 1003 or b = 1;\r\n1003 rows selected.\r\nExecution Plan\r\n\\-------------------------------------------------------\r\n\r\n0    select statement optimizer=shoose\r\n1   0 concatenation\r\n2   1  table access (by index rowid) of ‘unionvsor’\r\n3   2   index (range scan) of ‘UB’ (non-unique)\r\n4   1   table access (by index rowid) of ‘unionvsor’\r\n5   4   index (range scan) of ‘UA’ (non-unique)\r\nStatistics\r\n\r\n\\-------------------------------------------------------\r\n0 recursive calls\r\n0 db block gets\r\n   144 consistent gets\r\n   0 physical reads\r\n   0 redo size\r\n\r\n63749 bytes sent via SQL*Net to client\r\n\r\n 7751 bytes received via SQL* Net from client\r\n\r\n  68 SQL*Net roundtrips to/from client\r\n\r\n  0 sorts (memory)\r\n\r\n  0 sorts (disk)\r\n\r\n1003 rows processed\r\n\r\nSQL> select * from unionvsor /*2nd test*/\r\n\r\n2 where b = 1 or a = 1003;\r\n\r\n1003 rows selected.\r\n\r\nExecution Plan\r\n\r\n\\-------------------------------------------------------\r\n\r\n0    select statement optimizer=shoose\r\n1   0 concatenation\r\n2   1  table access (by index rowid) of ‘unionvsor’\r\n3   2   index (range scan) of ‘UA’ (non-unique)\r\n4   1   table access (by index rowid) of ‘unionvsor’\r\n5   4   index (range scan) of ‘UB’ (non-unique)\r\nStatistics\r\n\\-------------------------------------------------------\r\n0 recursive calls\r\n0 db block gets\r\n143 consistent gets\r\n0 physical reads\r\n0 redo size\r\n63749 bytes sent via SQL*Net to client\r\n 7751 bytes received via SQL* Net from client\r\n  68 SQL*Net roundtrips to/from client\r\n  0 sorts (memory)\r\n  0 sorts (disk)\r\n1003 rows processed\r\nSQL> select * from unionvsor /*3rd test*/\r\n2 where a = 1003\r\n3 union\r\n4 select * from unionvsor\r\n5 where b = 1;\r\n1003 rows selected.\r\nExecution Plan\r\n\r\n\\------------------------------------------------------\r\n\r\n0    select statement optimizer=choose\r\n1   0 sort (unique)\r\n2   1 union-all\r\n3   2 table access (by index rowid) of ‘unionvsor’\r\n4   3  index (range scan) of ‘UA’ (non-unique)\r\n5   2  table access (by index rowid) of ‘unionvsor’\r\n6   5  index (range scan) of ‘UB’ (non-unique)\r\nStatistics\r\n\\------------------------------------------------------\r\n0 recursive calls\r\n0 db block gets\r\n10 consistent gets\r\n0 physical reads\r\n0 redo size\r\n\r\n63735 bytes sent via SQL*Net to client\r\n7751 bytes received via SQL*Net from client\r\n68 SQL*Net roundtrips to/from client\r\n1 sorts (memory)\r\n0 sorts (disk)\r\n1003 rows processed\r\n\r\n用Union的效果可以从Consistent gets和SQL*Net的数据交换量的减少看出。\r\n### 三十七、用In来替换Or\r\n\r\n下面的查询可以被更有效率的语句替换：\r\n低效：\r\n```sql\r\nSelect …\r\nfrom location\r\nwhere loc_id = 10\r\nor loc_id = 20\r\nor loc_id = 30;\r\n```\r\n\r\n高效：\r\n```sql\r\nSelect …\r\nfrom location\r\nwhere loc_id in (10,20,30);\r\n```\r\n\r\n译者按：这是一条简单易记的规则，但是实际的执行效果还须检验，在Oracle8i下，两者的执行路径似乎是相同的。\r\n\r\n### 三十八、避免在索引列上使用Is null和Is not null\r\n\r\n避免在索引中使用任何可以为空的列，Oracle将无法使用该索引。对于单列索引，如果列包含空值，索引中将不存在此记录。对于复合索引，如果每个列都为空，索引中同样不存在此记录。如果至少有一个列不为空，则记录存在于索引中。\r\n\r\n例如：\r\n\r\n如果唯一性索引建立在表的A列和B列上，并且表中存在一条记录的A,B值为（123，null），Oracle将不接受下一条具有相同A,B值（123，null）的记录（插入）。然而如果所有的索引列都为空，Oracle将认为整个键值为空而空不等于空。因此你可以插入1000条具有相同键值的记录，当然它们都是空！\r\n\r\n因为空值不存在于索引列中，所以Where子句中对索引列进行空值比较将使Oracle停用该索引。\r\n例如：\r\n低效（索引失效）\r\n```sql\r\nSelect …\r\nfrom department\r\nwhere dept_code is not null;\r\n```\r\n\r\n高效（索引有效）\r\n```sql\r\nSelect …\r\nfrom department\r\nwhere dept_code >=0;\r\n```\r\n### 三十九、总是使用索引的第一个列\r\n\r\n如果索引是建立在多个列上，只有在它的第一个列（leading column）被Where子句引用时，优化器才会选择使用该索引。\r\n\r\n译者按：这也是一条简单而重要的规则。见以下实例。\r\n\r\nSQL> create table multiindexusage (inda number,indb number,descr varchar2(10));\r\nTable created.\r\nSQL> create index nultindex on multiindexusage (inda,indb);\r\nIndex created.\r\nSQL> set autotrace traceonly\r\nSQL> select * from multiindexusage where inda = 1;\r\nExecution Plan\r\n\\-----------------------------------------------------------\r\n\r\n0    select statement optimizer=choose\r\n1   0 table access (by index rowid) of ‘multiindexusage’\r\n2   1  index (range scan) of ‘multindex’ (non-unique)\r\nSQL> select * from multiindexusage where indb = 1;\r\nExecution Plan\r\n\\-----------------------------------------------------------\r\n0    select statement optimizer=choose\r\n1   0 table access (full) of ‘multiindexusage’\r\n很明显，当仅引用索引的第二个列时，优化器使用了全表扫描而忽略了索引。\r\n### 四十、Oracle内部操作\r\n\r\n当执行查询时，Oracle采用了内部的操作。下表显示了几种重要的内部操作。\r\n\r\n| Oracle  Clause                 | 内部操作                           |\r\n| ------------------------------ | ---------------------------------- |\r\n| Order  By                      | Sort  order by                     |\r\n| Union                          | Union-all                          |\r\n| Minus                          | Minus                              |\r\n| Intersect                      | Intersect                          |\r\n| Distinct,Minus,Intersect,Union | Sort  Unique                       |\r\n| Min,Max,Count                  | Sort  Aggregate                    |\r\n| Group  By                      | Sort  Group By                     |\r\n| Rownum                         | Count  or Count Stopkey            |\r\n| Queries  involving Joins       | Sort  Join,Merge Join,Nested Loops |\r\n| Connect  By                    | Connect  By                        |\r\n\r\n### 四十一、用Union-all替换Union（如果有可能的话）\r\n\r\n当SQL语句需要Union两个查询结果集合时，这两个结果集合会以Union-all的方式被合并，然后在输出最终结果前进行排序。\r\n\r\n如果用Union all替代Union，这样排序就不是必要了。效率就会因此得到提高。\r\n\r\n例如：\r\n\r\n低效：\r\n```sql\r\nSelect acct_num,balance_amt\r\nfrom debit_transactions\r\nwhere tran_date = ’31-DEC-95’\r\nunion\r\nSelect acct_num,balance_amt\r\nfrom debit_transactions\r\nwhere tran_date = ’31-DEC-95’\r\n```\r\n\r\n高效：\r\n```sql\r\nSelect acct_num,balance_amt\r\nfrom debit_transactions\r\nwhere tran_date = ’31-DEC-95’\r\nunion all\r\nSelect acct_num,balance_amt\r\nfrom debit_transactions\r\nwhere tran_date = ’31-DEC-95’\r\n```\r\n\r\n译者按：需要注意的是，Union all将重复输出两个结果集合中相同记录。因此各位还是要从业务需求分析使用Union all的可行性。\r\n\r\nUnion将对结果集合排序，这个操作会使用到Sort_area_size这块内存。对于这块内存的优化也是相当重要的。下面的SQL可以用来查询排序的消耗量。\r\n```sql\r\nselect substr(name, 1, 25) \"Sort Area Name\", \r\n	substr(value, 1, 15) \"Value\"\r\n	from v$sysstat\r\n where name like \'sort%\'\r\n```\r\n### 四十二、Oracle 9i启用Execution Plan的方法\r\n主要有四步：\r\nØ 创建表，通过utlxplan.sql脚本\r\nSQL> @?/rdbms/admin/utlxplan.sql\r\n\r\nØ 创建同义词，为了多个用户可以共享一个plan_table并授权给public\r\nSQL> create public synonym plan_table for plan_table;\r\nSQL> grant all on plan_table to public;\r\n\r\nØ 创建plustrace角色\r\nSQL> @?/sqlplus/admin/plustrce.sql执行这个脚本就可以了\r\n\r\nØ 将角色权限授予public\r\nSQL> grant plustrace to public;\r\n\r\n完成以上几步就可以使用autotrace功能\r\nSet timing on –显示执行时间\r\nSet autotrace on –查看执行计划和查询信息\r\nSet autotrace traceonly –只显示执行计划，但不显示查询输出\r\n### 四十三、使用提示（Hints）\r\n\r\n对于表的访问，可以使用两种Hints：Full和Rowid。\r\nØ Full hint告诉Oracle使用全表扫描的方式访问指定表。\r\n例如：\r\n```sql\r\nSelect */\\*+full(emp)\\*/**\r\n	from emp\r\n where empno = 7893; \r\n```\r\nØ Rowid hint告诉Oracle使用Table access by rowid的操作访问表。\r\n通常你需要采用Table access by rowid的方式，特别是当访问大表的时候，使用这种方式，你需要知道Rowid的值或者使用索引。\r\n\r\n如果一个大表没有被设定为缓存（Cached）表而你希望它的数据在查询结束时仍然停留在SGA中，你就可以使用Cache hint来告诉优化器把数据保留在SGA中。通常Cache hint和Full hint一起使用。\r\n例如：\r\nselect full(worker) cache(worker) from work;\r\n索引hint告诉Oracle使用基于索引的扫描方式。你不必说明具体的索引名称。\r\n例如：\r\nselect index(lodging) lodging from lodging\r\n where manager = \'bill gates\';\r\n在不使用hint的情况下，以上的查询应该也会使用索引，然而，如果该索引的重复值过多而你的优化器是CBO，优化器就可能忽略索引。在这种情况下，你可以用Index hint强制Oracle使用该索引。\r\nOracle hints还包括All_rows，First_rows，Rule，Use_NL，Use_merge,Use_hash等等。\r\n\r\n译者按：使用Hint，表示我们对Oracle优化器缺省的执行路径不满意，需要手工修改。这是一个很有技巧性的工作。我建议只针对特定的，少数的SQL进行hint的优化。对Oracle的优化器还是要有信息（特别是CBO）.\r\n\r\n### 四十四、用Where替代Order by\r\nOrder by子句只在两种严格的条件下使用索引。\r\nOrder by中所有的列必须饮食在相同的索引中并保持在索引中的排列顺序\r\nOrder by中所有的列必须定义为非空。\r\nWhere子句使用的索引和Order by子句中所使用的索引不能并列。\r\n例如：\r\n表Dept包含以下列：\r\nDept_code  PK   Not Null\r\nDept_desc     Not Null\r\nDept_type     Null\r\n非唯一性的索引（Dept_type）\r\n低效（索引不被使用）\r\n```sql\r\nSelect dept_code\r\nfrom dept\r\norder by dept_type\r\nExplain Plan:\r\nSort Order by\r\n   Table access full\r\n```\r\n高效（使用索引）\r\n```sql\r\nSelect dept_code\r\nfrom dept\r\nwhere dept_type>0\r\nExplain Plan:\r\nTable access by rowid on emp\r\n   Index range scan on dept_idx\r\n```\r\n译者按：Order by也能使用索引！这的确是个容易被忽略的知识点。我们来验证一下：\r\nSQL> select * from emp order by empno;\r\nExecution Plan\r\n\r\n\\------------------------------------------------\r\n0    select statement optimizer=choose\r\n1   0 table access (by index rowid) of ‘emp’\r\n2   1 index (full scan) of ‘empno’ (unique)\r\n### 四十五、避免改变索引列的类型\r\n当比较不同数据类型的数据时，Oracle自动对列进行简单的类型转换。\r\n假设Empno是一个数值类型的索引列。\r\n```sql\r\nSelect …\r\nfrom emp\r\nwhere empno = ‘123’;\r\n--实际上，经过Oracel类型转换，语句转化为：\r\nSelect …\r\nfrom emp\r\nwhere empno = to_number(‘123’)\r\n```\r\n幸运的是，类型转换没有发生在索引列上，索引的用途没有被改变。\r\n现在，假设EMP_TYPE是一个字符类型的索引列。\r\n```sql\r\nSelect …\r\nfrom emp\r\nwhere emp_type=123\r\n```\r\n这个语句被Oracle转换为：\r\n```sql\r\nSelect …\r\nfrom emp\r\nwhere to_number(emp_type)=123\r\n```\r\n因为内部发生的类型转换，这个索引将不会被用到！\r\n译者按：为了避免Oracle对你的SQL进行隐式的类型转换，最好把类型转换用显式表现出来。注意当字符和数值比较时，Oracle会优先转换数值类型到字符类型。\r\n\r\n### 四十六、需要当心的Where子句\r\n某些Select语句中的Where子句不使用索引。这里有一些例子。\r\nØ 在下面的例子里，’!=’将不使用索引。记住，索引只能告诉你什么存在于表中，而不能告诉你什么不存在于表中。\r\n\r\n不使用索引：\r\n```sql\r\nSelect account_name\r\nfrom transaction\r\nwhere amount !=0;\r\n```\r\n使用索引：\r\n```sql\r\nSelect account_name\r\nfrom transaction\r\nwhere amount > 0;\r\n```\r\n\r\nØ 下面的例子中，’||’是字符连接函数。就象其他函数那样，停用了索引。\r\n不使用索引：\r\n```sql\r\nSelect account_name,amount\r\nfrom transaction\r\nwhere account_name||account_type = ‘Amexa’;\r\n```\r\n使用索引：\r\n```sql\r\nSelect account_name,amount\r\nfrom transaction\r\nwhere account_name = ‘amex’ and account_type = ‘A’\r\n```\r\nØ 下面的例子中，’+’是数学函数。就象其他数学函数那样，停用了索引。\r\n\r\n不使用索引：\r\n```sql\r\nSelect account_name,amount\r\nfrom transaction\r\nwhere amount + 3000 > 5000;\r\n```\r\n使用索引：\r\n```sql\r\nSelect account_name,amount\r\nfrom transaction\r\nwhere amount > 2000;\r\n```\r\nØ 下面的例子中，相同的索引列不能互相比较，这将会启用全表扫描。\r\n不使用索引：\r\n```sql\r\nSelect account_name,amount\r\nfrom transaction\r\nwhere account_name = nvl(:acc_name,account_name);\r\n```\r\n使用索引：\r\n```sql\r\nSelect account_name,amount\r\nfrom transaction\r\nwhere account_anme like nvl(:acc_name,’%’);\r\n```\r\n\r\n译者按：如果一定要对使用函数的列启用索引，Oracle新的功能：基于函数的索引（Function-Based Index）也许是一个较好的方案。\r\nCreate index emp_i on emp (upper(ename)); /*建立基于函数的索引*/\r\nSelect * from emp where upper(ename) = ‘blacksnail’; /*将使用索引*/\r\n### 四十七、连接多个扫描\r\n如果你对一个列和一组有限的值进行比较，优化器可能执行多次扫描并对结果进行合并连接。\r\n例如：\r\n```sql\r\nSelect * \r\nfrom lodgingr\r\nwhere manage in (‘bill gates’,’ken muller’);\r\n```\r\n优化器可能将它转换成以下形式\r\n```sql\r\nSelect *\r\nfrom lodging\r\nwhere manager = ‘bill gates’ or manager = ‘ken muller’;\r\n```\r\n当选择执行路径时，优化器可能对每个条件采用Lodging$Manager上的索引范围扫描。返回的Rowid用来访问Lodging表的记录（通过Table access by rowid的方式）。最后两组记录以连接（Concatenation）的形式被组合成一个单一的集合。\r\nExplain Plan:\r\nSelect statement optimizer=choose\r\nConcatenation\r\nTable access (by index rowid) of lodging\r\nIndex (range scan) of lodging$Manager (non-unique)\r\nTable access (by index rowid) of lodging\r\nIndex (range scan) of lodging$Manager (non-unique)\r\n译者按：本节和第37节似乎有矛盾之处。\r\n### 四十八、CBO下使用更具选择性的索引\r\n\r\n基于成本的优化器（CBO,Cost-Based Optimizer）对索引的选择性进行判断来决定索引的使用是否能提高效率。\r\n如果索引有很高的选择性，那就是说对于每个不重复的索引键值，只对应数量很少的记录。\r\n比如，表中共有100条记录而其中有80个不重复的索引键值。这个索引的选择性就是80/100=0.8。选择性越高，通过索引键值检索出的记录就越少。\r\n如果索引的选择性很低，检索数据就需要大量的索引范围查询操作和Rowid访问表的操作。也许会比全表扫描的效率更低。\r\n译者按：\r\n下列经验请参阅：\r\nØ 如果检索数据量超过30%的表中记录数。使用索引将没有显著的效率提高。\r\nØ 在特定情况下，使用索引也许会比全表扫描慢，但这是同一个数量级上的区别。而通常情况下，使用索引比全表扫描要快几倍乃至几千倍！\r\n### 四十九、避免使用耗费资源的操作\r\n带有Distinct,Union,Minus,Intersect,Order by的SQL语句会启动SQL引擎执行耗费资源的排序（Sort）功能。Distinct需要一次排序操作，而其他的至少需要执行两次排序。\r\n\r\n例如，一个Union查询，其中每个查询都带有Group By子句，Group By会触发嵌入排序（Nested Sort）；这样，每个查询需要执行一次排序，然后在执行Union时，又一个唯一排序（Sort Unique）操作被执行而且它只能在前面的嵌入排序结束后才能开始执行。嵌入的排序的深度会大大影响查询的效率。\r\n通常还有Union,Minus,Intersect的SQL语句都可以用其他方式重写。\r\n译者按：如果你的数据库的Sort_area_size调配得好，使用Union，Minus,Intersect也是可以考虑的，毕竟它们的可读性很强。\r\n\r\n### 五十、优化Group By\r\n提高Group By语句的效率，可以通过将不需要的记录在Group by之前过滤掉。下面两个查询返回相同结果但第二个明显就快了许多。\r\n\r\n低效：\r\n```sql\r\nSelect job,avg(sal)\r\nfrom emp\r\ngroup by job\r\nhaving job = ‘president’\r\nor job = ‘manager’\r\n```\r\n高效：\r\n```sql\r\nSelect job,avg(sal)\r\nfrom emp\r\nwhere job = ‘president’\r\nor job = ‘manager’ group by job;\r\n```\r\n\r\n译者按：本节和14节相同。可略过。\r\n### 五十一、使用日期\r\n\r\n使用日期时，需要注意如果有超过5位小数加到日期上，这个日期会进到下一天。\r\n例如：\r\n```sql\r\nSelect to_date(’01-jan-93’+.99999)\r\nfrom dual;\r\nReturns:”01-jan-93 23:59:59”\r\nSelect to_date(’01-jan-93’+.999999)\r\nfrom dual;\r\n```\r\nReturns:”02-jan-93 00:00:00”\r\n\r\n译者按：虽然本节和SQL性能优化没有关系，但是作者的功力可见一般。\r\n\r\n### 五十二、使用显式的游标（Cursors）\r\n使用隐式的游标将会执行两次操作。第一次检索记录，第二次检查Too Many Rows这个Exception。而显式游标不执行第二次操作。\r\n\r\n### 五十三、优化Export和Import\r\n使用较大的Buffer（比如10MB，10240000）可以提高Export和Import的速度。\r\n\r\nOracle将尽可能地获取你所指定的内存大小，即使在内存不满足，也不会报错。这个值至少要和表中最大的列相当，否则列值会被截断。\r\n\r\n译者按：可以肯定的是，增加Buffer会大提高Export,Import的效率。（曾经碰到过一个Case，增加Buffer后，Import/Export快了10倍！）\r\n\r\n作者可能犯了一个错误：“这个值至少要和表中最大的列相当，否则列值会被截断”。其中最大的列也许是指最大的记录大小。\r\n\r\n关于Export/Import的优化，CSDN论坛中有一些总结性的帖子，比如关于Buffer参数，Commit参数等等，详情请查。\r\n\r\n分离表和索引\r\n\r\n总是将你的表和索引建立在不同的表空间内（Tablespaces）。决不要将不属于Oracle内部系统的对象存放到System表空间里。同时，确保数据表空间和索引表空间置于不同的硬盘上。\r\n\r\n译者按：“同时，确保数据表空间和索引表空间置于不同的硬盘上。”可能改为如下更为准确“同时，确保数据表空间和索引表空间置于不同的硬盘控制卡控制的硬盘上。”','11.jpg',3,'0',NULL,3,0,'Y');

/*Table structure for table `articaltag` */

DROP TABLE IF EXISTS `articaltag`;

CREATE TABLE `articaltag` (
  `ARTICAL_ID` int(11) NOT NULL COMMENT '文章编号',
  `TAG_ID` int(11) NOT NULL COMMENT '标签编号',
  PRIMARY KEY (`ARTICAL_ID`,`TAG_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='文章标签关联表';

/*Data for the table `articaltag` */

insert  into `articaltag`(`ARTICAL_ID`,`TAG_ID`) values (3,1),(6,3),(7,3),(10,4),(11,5),(12,1),(12,5),(12,6),(13,1),(14,7),(15,5),(15,6),(16,6),(16,9),(20,10);

/*Table structure for table `likerecord` */

DROP TABLE IF EXISTS `likerecord`;

CREATE TABLE `likerecord` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `LIKE_DATE` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '访问日期',
  `IP_ADDRESS` varchar(32) COLLATE utf8_bin NOT NULL COMMENT 'IP地址',
  `ARTICAL_ID` int(11) NOT NULL COMMENT '文章编号',
  `LAST_LIKE_TIME` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '最近一次点赞时间',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='点赞记录表';

/*Data for the table `likerecord` */

insert  into `likerecord`(`ID`,`LIKE_DATE`,`IP_ADDRESS`,`ARTICAL_ID`,`LAST_LIKE_TIME`) values (8,'2020-04-28','127.0.0.1',18,'2020-04-28 21:34:05'),(9,'2020-04-28','127.0.0.1',17,'2020-04-28 21:34:14'),(10,'2020-04-29','127.0.0.1',8,'2020-04-29 09:21:29'),(11,'2020-04-29','127.0.0.1',3,'2020-04-29 09:56:28'),(12,'2020-04-30','127.0.0.1',16,'2020-04-30 16:15:31'),(13,'2020-05-08','127.0.0.1',15,'2020-05-08 12:15:01');

/*Table structure for table `link` */

DROP TABLE IF EXISTS `link`;

CREATE TABLE `link` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `WEBNAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '网站名称',
  `MOTTO` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '介绍',
  `URL` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '网站地址',
  `WEBICON` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '网站图标',
  `WEBMASTER` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '站长姓名',
  `WECHAT` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '微信号',
  `PHONE` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '站长手机号',
  `EMAIL` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '站长邮箱',
  `TYPE` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '分类',
  `STATUS` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '状态',
  `CREATETIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='友情链接表';

/*Data for the table `link` */

insert  into `link`(`ID`,`WEBNAME`,`MOTTO`,`URL`,`WEBICON`,`WEBMASTER`,`WECHAT`,`PHONE`,`EMAIL`,`TYPE`,`STATUS`,`CREATETIME`) values (1,'程序猿张先森','多年以后，愿你的城市，有清风，有烈酒，也有人是你的归途','https://www.zhyocean.cn/','53D2A391F96F4D60A1DB8AE32279C5A7.png','张海洋',NULL,NULL,'1125694337@qq.com','1','1','2020-04-26 11:13:57'),(2,'听雨阁','一个java程序员的个人博客，记录博主的学习,生活中的一些有趣的事，并分享Java方面技术和源码。 ','http://www.long225.cn/','E90B0CFE37E54F76B933573734D15095.png','long225',NULL,NULL,'unkonwn@163.com','1','1','2020-04-26 11:14:06'),(3,'宋子宪博客','冬日虽冷，终有阳光！','https://songzixian.com/','FB97470028914AFB9BAB77D50531DF06.png','宋子宪',NULL,NULL,'songzixian@github.com','1','1','2020-04-26 11:18:01'),(4,'程序员DD','本博客主要分享作者原创的技术文章以及在日常工作和学习中读过的好文','http://blog.didispace.com/','FF24658D39804C50994A917873FC918C.png','程序员DD',NULL,NULL,'didispace@gitee.com','2','1','2020-04-26 11:42:13'),(5,'百度首页','知识搜索引擎知识搜索引擎知识搜索引擎知识搜索引擎知识搜索引擎知识搜索引擎知识搜索引擎知识搜索引擎','www.baidu.com','0647C4CF594B4756A3754C8DC4A5A10E.jpg','百度',NULL,NULL,'baidu@github.com','3','1','2020-04-29 10:23:13');

/*Table structure for table `message` */

DROP TABLE IF EXISTS `message`;

CREATE TABLE `message` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '消息编号',
  `ARTICAL_ID` int(11) DEFAULT NULL COMMENT '文章编号',
  `ACCOUNT` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '用户名',
  `CONTENT` varchar(1024) COLLATE utf8_bin DEFAULT NULL COMMENT '留言内容',
  `MESSAGE_TIME` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '留言时间',
  `STATUS` varchar(8) COLLATE utf8_bin DEFAULT NULL COMMENT '状态',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='留言表';

/*Data for the table `message` */

insert  into `message`(`ID`,`ARTICAL_ID`,`ACCOUNT`,`CONTENT`,`MESSAGE_TIME`,`STATUS`) values (1,17,'hairui623968','哈哈','2020-04-28 09:04:24','1');

/*Table structure for table `messagereply` */

DROP TABLE IF EXISTS `messagereply`;

CREATE TABLE `messagereply` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `MSGID` int(11) DEFAULT NULL COMMENT '消息编号',
  `FROMACCOUNT` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '发消息用户',
  `TOACCOUNT` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '收消息用户',
  `CONTENT` varchar(1024) COLLATE utf8_bin DEFAULT NULL COMMENT '留言内容',
  `REPLYTIME` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '回复时间',
  `STATUS` varchar(8) COLLATE utf8_bin DEFAULT NULL COMMENT '状态',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='留言回复表';

/*Data for the table `messagereply` */

/*Table structure for table `myinfo` */

DROP TABLE IF EXISTS `myinfo`;

CREATE TABLE `myinfo` (
  `ID` int(11) NOT NULL COMMENT '编号',
  `NICKNAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '网名',
  `NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '站长姓名',
  `WEBNAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '网站名称',
  `OCCUPATION` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '职业',
  `ADDRESS` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '地址',
  `EMAIL` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '邮箱',
  `WEBSITE` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '网址',
  `QQ` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT 'QQ号码',
  `WECHAT` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '微信号',
  `WEBICON` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '网站图标',
  `MOTTO` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '座右铭',
  `PROPHOTO` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '头像',
  `GITEE` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT 'gitee',
  `GITHUB` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT 'github',
  `WEIBO` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '新浪微博',
  `BRANDIMG` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '网站LOGO',
  `RECORD` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '备案号',
  `CREATETIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='我的信息表';

/*Data for the table `myinfo` */

insert  into `myinfo`(`ID`,`NICKNAME`,`NAME`,`WEBNAME`,`OCCUPATION`,`ADDRESS`,`EMAIL`,`WEBSITE`,`QQ`,`WECHAT`,`WEBICON`,`MOTTO`,`PROPHOTO`,`GITEE`,`GITHUB`,`WEIBO`,`BRANDIMG`,`RECORD`,`CREATETIME`) values (1,'老干部','李海瑞','程序员小站','全栈工程师','陕西省-西安市','lihairuizone@163.com','http://laoganbu.site','1234567890','623968haiuri','favicon.ico','生活最大的幸福在于，我们自己的未来我们自己可以去选择，去努力，去亲手创造。这正是件有趣的事情了。','avatar.jpg','www.gitee.com/112233','https://github.com/123456','https://weibo.com/12345','brand2.jpg','Copyright @ 2018 - 2020 李元霸','2019-08-03 17:01:35');

/*Table structure for table `resetpwdlog` */

DROP TABLE IF EXISTS `resetpwdlog`;

CREATE TABLE `resetpwdlog` (
  `ACCOUNT` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '帐号',
  `TOKEN` varchar(256) COLLATE utf8_bin NOT NULL COMMENT 'token码',
  `EMAIL` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '邮箱',
  `SUBMIT_TIME` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '提交时间',
  PRIMARY KEY (`ACCOUNT`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='重置密码记录';

/*Data for the table `resetpwdlog` */

insert  into `resetpwdlog`(`ACCOUNT`,`TOKEN`,`EMAIL`,`SUBMIT_TIME`) values ('hairui623968','7fdDijl98fdSSuF609766lsJDaj18FH',NULL,'2020-05-07 16:25:52');

/*Table structure for table `s_resc_manage` */

DROP TABLE IF EXISTS `s_resc_manage`;

CREATE TABLE `s_resc_manage` (
  `RESC_ICON` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '资源图标',
  `RESC_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '资源名称',
  `RESC_ID` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '资源编号',
  `ORDER_ID` int(11) NOT NULL COMMENT '排序编号',
  `USE_FLAG` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '使用标志 on off',
  PRIMARY KEY (`RESC_ID`,`ORDER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='资源表';

/*Data for the table `s_resc_manage` */

insert  into `s_resc_manage`(`RESC_ICON`,`RESC_NAME`,`RESC_ID`,`ORDER_ID`,`USE_FLAG`) values ('&#xe63c','内容管理','contentManagement',1,'Y'),('&#xe66f','用户中心','memberCenter',2,'Y'),('&#xe620','系统设置','systemeSttings',3,'Y');

/*Table structure for table `s_resc_menu` */

DROP TABLE IF EXISTS `s_resc_menu`;

CREATE TABLE `s_resc_menu` (
  `TARGET` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '目标地',
  `SPREAD` tinyint(1) DEFAULT NULL COMMENT '是否展开 true false',
  `HREF` varchar(200) CHARACTER SET utf8 NOT NULL COMMENT '链接地址',
  `ICON` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '菜单图标',
  `TITLE` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '名称',
  `RESC_ID` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '资源编号',
  `ORDER_ID` int(11) DEFAULT NULL COMMENT '排序编号',
  `USE_FLAG` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '使用标志 on off',
  PRIMARY KEY (`HREF`,`RESC_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='菜单表';

/*Data for the table `s_resc_menu` */

insert  into `s_resc_menu`(`TARGET`,`SPREAD`,`HREF`,`ICON`,`TITLE`,`RESC_ID`,`ORDER_ID`,`USE_FLAG`) values (NULL,0,'/manage/album/list','&#xe64a','相册管理','contentManagement',5,'Y'),(NULL,0,'/manage/artical/list','&#xe642','文章管理','contentManagement',1,'Y'),(NULL,0,'/manage/config','&#xe614','网站配置中心','systemeSttings',3,'Y'),(NULL,0,'/manage/link/list','&#xe64c','友情链接','contentManagement',4,'Y'),(NULL,0,'/manage/log/list','&#xe61c','系统日志','systemeSttings',99,'N'),(NULL,0,'/manage/parameter','&#xe631','系统基本参数','systemeSttings',4,'Y'),(NULL,0,'/manage/sRescManage/list','&#xe62a','导航菜单管理','systemeSttings',1,'Y'),(NULL,0,'/manage/sRescMenu/list','&#xe63c','功能菜单管理','systemeSttings',2,'Y'),(NULL,0,'/manage/tag/list','&#xe656','标签管理','contentManagement',3,'Y'),(NULL,0,'/manage/type/list','&#xe653','分类管理','contentManagement',2,'Y'),(NULL,0,'/manage/user/list','&#xe612','用户中心','memberCenter',1,'Y'),(NULL,0,'manage/book/list','&#xe705','推荐书籍','contentManagement',99,'N');

/*Table structure for table `tag` */

DROP TABLE IF EXISTS `tag`;

CREATE TABLE `tag` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `NAME` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '标签名称',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='标签表';

/*Data for the table `tag` */

insert  into `tag`(`ID`,`NAME`) values (1,'Java'),(2,'Spring'),(3,'运维'),(4,'Maven'),(5,'Web项目'),(6,'Springboot'),(7,'Git'),(8,'SVN'),(9,'logback'),(10,'Oracle');

/*Table structure for table `type` */

DROP TABLE IF EXISTS `type`;

CREATE TABLE `type` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '分类名称',
  `SHOW_FLAG` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '是否展示',
  `INTRODUCTION` varchar(1024) CHARACTER SET utf8 DEFAULT NULL COMMENT '介绍',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='分类表';

/*Data for the table `type` */

insert  into `type`(`ID`,`NAME`,`SHOW_FLAG`,`INTRODUCTION`) values (1,'Java','Y',NULL),(2,'操作系统','Y',NULL),(3,'数据库','Y',NULL),(4,'Spring','Y',NULL),(5,'金融行业','Y',NULL),(6,'开发运维','Y',NULL),(7,'前端技术','Y',NULL),(8,'数据结构','Y',NULL),(9,'算法','Y',NULL),(10,'行业杂谈','Y','行业杂谈');

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `ACCOUNT` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '帐号',
  `PASSWORD` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '密码',
  `NICKNAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '昵称',
  `SEX` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '性别',
  `AGE` int(11) DEFAULT NULL COMMENT '年龄',
  `NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '真实姓名',
  `PROPHOTO` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '头像',
  `EMAIL` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '邮箱',
  `MOBILE` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '手机号',
  `TYPE` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户类型',
  `CREATE_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建时间',
  `UPDATE_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '更新时间',
  `STATUS` varchar(8) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户状态',
  `LAST_LOGIN_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '上次登录时间',
  `ERROR_COUNT` int(11) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='用户信息表';

/*Data for the table `user` */

insert  into `user`(`ID`,`ACCOUNT`,`PASSWORD`,`NICKNAME`,`SEX`,`AGE`,`NAME`,`PROPHOTO`,`EMAIL`,`MOBILE`,`TYPE`,`CREATE_TIME`,`UPDATE_TIME`,`STATUS`,`LAST_LOGIN_TIME`,`ERROR_COUNT`) values (1,'hairui623968','D9677212177DEA730A9FA2370965267F','骑鱼的佩奇','M',28,'李海瑞','user4.jpg','lihairuizone@sina.com','15129887820','admin','2020-04-20 11:38:26','2020-05-07 16:27:34','0','2020-05-13 16:01:23',0);

/*Table structure for table `viewrecord` */

DROP TABLE IF EXISTS `viewrecord`;

CREATE TABLE `viewrecord` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `VISIT_DATE` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '访问日期',
  `IP_ADDRESS` varchar(32) COLLATE utf8_bin NOT NULL COMMENT 'IP地址',
  `ARTICAL_ID` int(11) NOT NULL COMMENT '文章编号',
  `LAST_VISIT_TIME` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '最近一次访问时间',
  `VISIT_COUNT` int(11) DEFAULT NULL COMMENT '访问次数',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='文章查看记录表';

/*Data for the table `viewrecord` */

insert  into `viewrecord`(`ID`,`VISIT_DATE`,`IP_ADDRESS`,`ARTICAL_ID`,`LAST_VISIT_TIME`,`VISIT_COUNT`) values (1,'2020-04-28','127.0.0.1',18,'2020-04-28 21:37:12',21),(2,'2020-04-28','127.0.0.1',17,'2020-04-28 21:34:13',4),(3,'2020-04-28','127.0.0.1',15,'2020-04-28 21:30:47',2),(4,'2020-04-28','127.0.0.1',12,'2020-04-28 17:44:02',1),(5,'2020-04-28','127.0.0.1',16,'2020-04-28 21:30:02',1),(6,'2020-04-28','127.0.0.1',14,'2020-04-28 21:31:29',1),(7,'2020-04-29','127.0.0.1',18,'2020-04-29 09:51:52',1),(8,'2020-04-29','127.0.0.1',16,'2020-04-29 08:48:50',1),(9,'2020-04-29','127.0.0.1',15,'2020-04-29 09:04:58',2),(10,'2020-04-29','127.0.0.1',17,'2020-04-29 09:52:02',2),(11,'2020-04-29','127.0.0.1',8,'2020-04-29 09:21:25',1),(12,'2020-04-29','127.0.0.1',1,'2020-04-29 09:54:13',1),(13,'2020-04-29','127.0.0.1',2,'2020-04-29 09:54:17',1),(14,'2020-04-29','127.0.0.1',3,'2020-04-29 10:00:33',1),(15,'2020-04-30','127.0.0.1',19,'2020-04-30 16:15:02',1),(16,'2020-04-30','127.0.0.1',17,'2020-04-30 16:15:17',1),(17,'2020-04-30','127.0.0.1',16,'2020-04-30 16:15:26',1),(18,'2020-05-06','127.0.0.1',2,'2020-05-06 17:36:27',1),(19,'2020-05-07','127.0.0.1',19,'2020-05-07 16:48:11',1),(20,'2020-05-07','127.0.0.1',18,'2020-05-07 16:57:25',1),(21,'2020-05-07','127.0.0.1',10,'2020-05-07 17:51:23',1),(22,'2020-05-08','127.0.0.1',12,'2020-05-08 09:19:07',1),(23,'2020-05-08','127.0.0.1',17,'2020-05-08 17:24:13',2),(24,'2020-05-08','127.0.0.1',15,'2020-05-08 17:24:37',2),(25,'2020-05-08','127.0.0.1',18,'2020-05-08 17:24:08',1),(26,'2020-05-08','127.0.0.1',16,'2020-05-08 17:24:23',1),(27,'2020-05-08','127.0.0.1',14,'2020-05-08 17:25:15',1),(28,'2020-05-09','127.0.0.1',20,'2020-05-09 15:43:50',1),(29,'2020-05-09','127.0.0.1',19,'2020-05-09 13:31:12',1),(30,'2020-05-13','127.0.0.1',20,'2020-05-13 16:50:17',2),(31,'2020-05-13','127.0.0.1',7,'2020-05-13 09:07:42',1);

/*Table structure for table `visitrecord` */

DROP TABLE IF EXISTS `visitrecord`;

CREATE TABLE `visitrecord` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `VISIT_DATE` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '访问日期',
  `IP_ADDRESS` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT 'IP地址',
  `LAST_VISIT_TIME` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '最近访问时间',
  `VISIT_COUNT` int(11) DEFAULT NULL COMMENT '访问次数',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='网站访问记录表';

/*Data for the table `visitrecord` */

insert  into `visitrecord`(`ID`,`VISIT_DATE`,`IP_ADDRESS`,`LAST_VISIT_TIME`,`VISIT_COUNT`) values (1,'2020-04-27','127.0.0.1','2020-04-27 22:46:52',3),(2,'2020-04-27','127.0.1.1','2020-04-27 22:37:30',6),(3,'2020-04-25','127.0.1.1','2020-04-27 22:35:46',20),(4,'2020-04-18','192.168.1.1','2020-04-15 08:35:46',1),(5,'2020-04-28','127.0.0.1','2020-04-28 21:37:15',2),(6,'2020-04-29','127.0.0.1','2020-04-29 13:35:01',1),(7,'2020-04-30','127.0.0.1','2020-04-30 17:02:15',1),(8,'2020-05-06','127.0.0.1','2020-05-06 17:36:28',1),(9,'2020-05-07','127.0.0.1','2020-05-07 17:55:50',1),(10,'2020-05-08','127.0.0.1','2020-05-08 17:26:43',2),(11,'2020-05-09','127.0.0.1','2020-05-09 16:12:50',1),(12,'2020-05-11','127.0.0.1','2020-05-11 17:33:17',1),(13,'2020-05-13','127.0.0.1','2020-05-13 17:45:20',1);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
